botched copyright
[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
d0ab932c 8static char *sccsid = "@(#)cmd2.c 5.2 (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);
233 t = mp->m_lines - 2;
234 readline(mesf, linebuf);
235 while (t-- > 0) {
236 fgets(linebuf, BUFSIZ, mesf);
237 fputs(linebuf, obuf);
238 cc += strlen(linebuf);
239 }
240 lc += mp->m_lines - 2;
241 mp->m_flag |= MSAVED;
242 }
243 fflush(obuf);
244 if (ferror(obuf))
245 perror(file);
246 fclose(obuf);
247 printf("%s %d/%d\n", disp, lc, cc);
248 return(0);
249}
250
251/*
252 * Snarf the file from the end of the command line and
253 * return a pointer to it. If there is no file attached,
254 * just return NOSTR. Put a null in front of the file
255 * name so that the message list processing won't see it,
256 * unless the file name is the only thing on the line, in
257 * which case, return 0 in the reference flag variable.
258 */
259
260char *
261snarf(linebuf, flag)
262 char linebuf[];
263 int *flag;
264{
265 register char *cp;
266
267 *flag = 1;
268 cp = strlen(linebuf) + linebuf - 1;
269
270 /*
271 * Strip away trailing blanks.
272 */
273
274 while (*cp == ' ' && cp > linebuf)
275 cp--;
276 *++cp = 0;
277
278 /*
279 * Now search for the beginning of the file name.
280 */
281
282 while (cp > linebuf && !any(*cp, "\t "))
283 cp--;
284 if (*cp == '\0') {
285 printf("No file specified.\n");
286 return(NOSTR);
287 }
288 if (any(*cp, " \t"))
289 *cp++ = 0;
290 else
291 *flag = 0;
292 return(cp);
293}
294
295/*
296 * Delete messages.
297 */
298
299delete(msgvec)
300 int msgvec[];
301{
302 return(delm(msgvec));
303}
304
305/*
306 * Delete messages, then type the new dot.
307 */
308
309deltype(msgvec)
310 int msgvec[];
311{
312 int list[2];
12c002da 313 int lastdot;
a13d1f28 314
12c002da 315 lastdot = dot - &message[0] + 1;
a13d1f28
KS
316 if (delm(msgvec) >= 0) {
317 list[0] = dot - &message[0];
318 list[0]++;
12c002da
KS
319 if (list[0] > lastdot) {
320 touch(list[0]);
321 list[1] = NULL;
322 return(type(list));
323 }
324 printf("At EOF\n");
325 return(0);
a13d1f28
KS
326 }
327 else {
328 printf("No more messages\n");
329 return(0);
330 }
331}
332
333/*
334 * Delete the indicated messages.
335 * Set dot to some nice place afterwards.
336 * Internal interface.
337 */
338
339delm(msgvec)
340 int *msgvec;
341{
342 register struct message *mp;
343 register *ip, mesg;
344 int last;
345
346 last = NULL;
347 for (ip = msgvec; *ip != NULL; ip++) {
348 mesg = *ip;
349 touch(mesg);
350 mp = &message[mesg-1];
3c139aaf
KS
351 mp->m_flag |= MDELETED|MTOUCH;
352 mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
a13d1f28
KS
353 last = mesg;
354 }
355 if (last != NULL) {
356 dot = &message[last-1];
357 last = first(0, MDELETED);
358 if (last != NULL) {
359 dot = &message[last-1];
360 return(0);
361 }
362 else {
363 dot = &message[0];
364 return(-1);
365 }
366 }
367
368 /*
369 * Following can't happen -- it keeps lint happy
370 */
371
372 return(-1);
373}
374
375/*
376 * Undelete the indicated messages.
377 */
378
379undelete(msgvec)
380 int *msgvec;
381{
382 register struct message *mp;
383 register *ip, mesg;
384
385 for (ip = msgvec; ip-msgvec < msgCount; ip++) {
386 mesg = *ip;
387 if (mesg == 0)
388 return;
389 touch(mesg);
390 mp = &message[mesg-1];
391 dot = mp;
392 mp->m_flag &= ~MDELETED;
393 }
394}
395
396/*
397 * Interactively dump core on "core"
398 */
399
400core()
401{
402 register int pid;
403 int status;
404
405 if ((pid = vfork()) == -1) {
406 perror("fork");
407 return(1);
408 }
409 if (pid == 0) {
64df7743 410 sigchild();
a13d1f28
KS
411 abort();
412 _exit(1);
413 }
414 printf("Okie dokie");
415 fflush(stdout);
416 while (wait(&status) != pid)
417 ;
418 if (status & 0200)
419 printf(" -- Core dumped\n");
420 else
421 printf("\n");
422}
47e37b8b
KS
423
424/*
425 * Clobber as many bytes of stack as the user requests.
426 */
427clobber(argv)
428 char **argv;
429{
430 register int times;
431
432 if (argv[0] == 0)
433 times = 1;
434 else
435 times = (atoi(argv[0]) + 511) / 512;
ab61fde0 436 clob1(times);
47e37b8b
KS
437}
438
439/*
440 * Clobber the stack.
441 */
ab61fde0 442clob1(n)
47e37b8b
KS
443{
444 char buf[512];
445 register char *cp;
446
447 if (n <= 0)
448 return;
449 for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
450 ;
ab61fde0 451 clob1(n - 1);
47e37b8b 452}
eed74ec1 453
46053c99
S
454/*
455 * Add the given header fields to the retained list.
456 * If no arguments, print the current list of retained fields.
457 */
458retfield(list)
459 char *list[];
460{
461 char field[BUFSIZ];
462 register int h;
463 register struct ignore *igp;
464 char **ap;
465
466 if (argcount(list) == 0)
467 return(retshow());
468 for (ap = list; *ap != 0; ap++) {
469 istrcpy(field, *ap);
470
471 if (member(field, retain))
472 continue;
473
474 h = hash(field);
475 igp = (struct ignore *) calloc(1, sizeof (struct ignore));
476 igp->i_field = calloc(strlen(field) + 1, sizeof (char));
477 strcpy(igp->i_field, field);
478 igp->i_link = retain[h];
479 retain[h] = igp;
480 nretained++;
481 }
482 return(0);
483}
484
485/*
486 * Print out all currently retained fields.
487 */
488retshow()
489{
490 register int h, count;
491 struct ignore *igp;
492 char **ap, **ring;
493 int igcomp();
494
495 count = 0;
496 for (h = 0; h < HSHSIZE; h++)
497 for (igp = retain[h]; igp != 0; igp = igp->i_link)
498 count++;
499 if (count == 0) {
500 printf("No fields currently being retained.\n");
501 return(0);
502 }
503 ring = (char **) salloc((count + 1) * sizeof (char *));
504 ap = ring;
505 for (h = 0; h < HSHSIZE; h++)
506 for (igp = retain[h]; igp != 0; igp = igp->i_link)
507 *ap++ = igp->i_field;
508 *ap = 0;
509 qsort(ring, count, sizeof (char *), igcomp);
510 for (ap = ring; *ap != 0; ap++)
511 printf("%s\n", *ap);
512 return(0);
513}
514
eed74ec1
KS
515/*
516 * Add the given header fields to the ignored list.
517 * If no arguments, print the current list of ignored fields.
518 */
519igfield(list)
520 char *list[];
521{
522 char field[BUFSIZ];
523 register int h;
524 register struct ignore *igp;
525 char **ap;
526
527 if (argcount(list) == 0)
528 return(igshow());
529 for (ap = list; *ap != 0; ap++) {
93be40ac
KS
530 if (isign(*ap))
531 continue;
eed74ec1
KS
532 istrcpy(field, *ap);
533 h = hash(field);
534 igp = (struct ignore *) calloc(1, sizeof (struct ignore));
535 igp->i_field = calloc(strlen(field) + 1, sizeof (char));
536 strcpy(igp->i_field, field);
537 igp->i_link = ignore[h];
538 ignore[h] = igp;
539 }
540 return(0);
541}
542
543/*
544 * Print out all currently ignored fields.
545 */
546igshow()
547{
93be40ac 548 register int h, count;
eed74ec1 549 struct ignore *igp;
93be40ac
KS
550 char **ap, **ring;
551 int igcomp();
eed74ec1 552
93be40ac 553 count = 0;
eed74ec1 554 for (h = 0; h < HSHSIZE; h++)
93be40ac
KS
555 for (igp = ignore[h]; igp != 0; igp = igp->i_link)
556 count++;
557 if (count == 0) {
eed74ec1 558 printf("No fields currently being ignored.\n");
93be40ac
KS
559 return(0);
560 }
3d1ce6bb 561 ring = (char **) salloc((count + 1) * sizeof (char *));
93be40ac
KS
562 ap = ring;
563 for (h = 0; h < HSHSIZE; h++)
564 for (igp = ignore[h]; igp != 0; igp = igp->i_link)
565 *ap++ = igp->i_field;
566 *ap = 0;
567 qsort(ring, count, sizeof (char *), igcomp);
568 for (ap = ring; *ap != 0; ap++)
569 printf("%s\n", *ap);
eed74ec1
KS
570 return(0);
571}
93be40ac
KS
572
573/*
574 * Compare two names for sorting ignored field list.
575 */
576igcomp(l, r)
577 char **l, **r;
578{
579
580 return(strcmp(*l, *r));
581}