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