install depends on ksu
[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
2ee3bce2 19static char sccsid[] = "@(#)cmd2.c 5.11 (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{
470c33f3 141 register int *ip;
a13d1f28 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 172 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
470c33f3
EW
173 mp = &message[*ip - 1];
174 touch(mp);
2de8fc95 175 if (send(mp, obuf, ignore, NOSTR) < 0) {
a13d1f28
KS
176 perror(file);
177 fclose(obuf);
178 return(1);
179 }
c7db23a4
KS
180 if (mark)
181 mp->m_flag |= MSAVED;
a13d1f28
KS
182 }
183 fflush(obuf);
184 if (ferror(obuf))
185 perror(file);
186 fclose(obuf);
2de8fc95 187 printf("%s\n", disp);
a13d1f28
KS
188 return(0);
189}
190
191/*
192 * Write the indicated messages at the end of the passed
193 * file name, minus header and trailing blank line.
194 */
195
196swrite(str)
197 char str[];
198{
a13d1f28 199
2de8fc95 200 return save1(str, 1, "write", ignoreall);
a13d1f28
KS
201}
202
203/*
204 * Snarf the file from the end of the command line and
205 * return a pointer to it. If there is no file attached,
206 * just return NOSTR. Put a null in front of the file
207 * name so that the message list processing won't see it,
208 * unless the file name is the only thing on the line, in
209 * which case, return 0 in the reference flag variable.
210 */
211
212char *
213snarf(linebuf, flag)
214 char linebuf[];
215 int *flag;
216{
217 register char *cp;
218
219 *flag = 1;
220 cp = strlen(linebuf) + linebuf - 1;
221
222 /*
223 * Strip away trailing blanks.
224 */
225
828615a1 226 while (cp > linebuf && isspace(*cp))
a13d1f28
KS
227 cp--;
228 *++cp = 0;
229
230 /*
231 * Now search for the beginning of the file name.
232 */
233
828615a1 234 while (cp > linebuf && !isspace(*cp))
a13d1f28
KS
235 cp--;
236 if (*cp == '\0') {
237 printf("No file specified.\n");
238 return(NOSTR);
239 }
828615a1 240 if (isspace(*cp))
a13d1f28
KS
241 *cp++ = 0;
242 else
243 *flag = 0;
244 return(cp);
245}
246
247/*
248 * Delete messages.
249 */
250
251delete(msgvec)
252 int msgvec[];
253{
2ee3bce2
EW
254 delm(msgvec);
255 return 0;
a13d1f28
KS
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 269 if (delm(msgvec) >= 0) {
470c33f3 270 list[0] = dot - &message[0] + 1;
12c002da 271 if (list[0] > lastdot) {
470c33f3 272 touch(dot);
12c002da
KS
273 list[1] = NULL;
274 return(type(list));
275 }
276 printf("At EOF\n");
2ee3bce2 277 } else
a13d1f28 278 printf("No more messages\n");
2ee3bce2 279 return(0);
a13d1f28
KS
280}
281
282/*
283 * Delete the indicated messages.
284 * Set dot to some nice place afterwards.
285 * Internal interface.
286 */
287
288delm(msgvec)
289 int *msgvec;
290{
291 register struct message *mp;
470c33f3 292 register *ip;
a13d1f28
KS
293 int last;
294
295 last = NULL;
296 for (ip = msgvec; *ip != NULL; ip++) {
470c33f3
EW
297 mp = &message[*ip - 1];
298 touch(mp);
3c139aaf
KS
299 mp->m_flag |= MDELETED|MTOUCH;
300 mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
470c33f3 301 last = *ip;
a13d1f28
KS
302 }
303 if (last != NULL) {
304 dot = &message[last-1];
305 last = first(0, MDELETED);
306 if (last != NULL) {
307 dot = &message[last-1];
308 return(0);
309 }
310 else {
311 dot = &message[0];
312 return(-1);
313 }
314 }
315
316 /*
317 * Following can't happen -- it keeps lint happy
318 */
319
320 return(-1);
321}
322
323/*
324 * Undelete the indicated messages.
325 */
326
327undelete(msgvec)
328 int *msgvec;
329{
330 register struct message *mp;
470c33f3
EW
331 register *ip;
332
333 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
334 mp = &message[*ip - 1];
335 touch(mp);
a13d1f28
KS
336 dot = mp;
337 mp->m_flag &= ~MDELETED;
338 }
339}
340
341/*
342 * Interactively dump core on "core"
343 */
344
345core()
346{
322c8626
EW
347 int pid;
348 extern union wait wait_status;
a13d1f28 349
322c8626
EW
350 switch (pid = vfork()) {
351 case -1:
a13d1f28
KS
352 perror("fork");
353 return(1);
322c8626 354 case 0:
a13d1f28
KS
355 abort();
356 _exit(1);
357 }
358 printf("Okie dokie");
359 fflush(stdout);
322c8626
EW
360 wait_child(pid);
361 if (wait_status.w_coredump)
362 printf(" -- Core dumped.\n");
a13d1f28 363 else
322c8626 364 printf(" -- Can't dump core.\n");
828615a1 365 return 0;
a13d1f28 366}
47e37b8b
KS
367
368/*
369 * Clobber as many bytes of stack as the user requests.
370 */
371clobber(argv)
372 char **argv;
373{
374 register int times;
375
376 if (argv[0] == 0)
377 times = 1;
378 else
379 times = (atoi(argv[0]) + 511) / 512;
ab61fde0 380 clob1(times);
47e37b8b
KS
381}
382
383/*
384 * Clobber the stack.
385 */
ab61fde0 386clob1(n)
47e37b8b
KS
387{
388 char buf[512];
389 register char *cp;
390
391 if (n <= 0)
392 return;
393 for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
394 ;
ab61fde0 395 clob1(n - 1);
47e37b8b 396}
eed74ec1 397
46053c99
S
398/*
399 * Add the given header fields to the retained list.
400 * If no arguments, print the current list of retained fields.
401 */
402retfield(list)
403 char *list[];
404{
46053c99 405
887efe38 406 return ignore1(list, ignore + 1, "retained");
46053c99
S
407}
408
409/*
887efe38
EW
410 * Add the given header fields to the ignored list.
411 * If no arguments, print the current list of ignored fields.
46053c99 412 */
887efe38
EW
413igfield(list)
414 char *list[];
46053c99 415{
46053c99 416
887efe38 417 return ignore1(list, ignore, "ignored");
46053c99
S
418}
419
887efe38
EW
420saveretfield(list)
421 char *list[];
422{
423
424 return ignore1(list, saveignore + 1, "retained");
425}
426
427saveigfield(list)
eed74ec1
KS
428 char *list[];
429{
887efe38
EW
430
431 return ignore1(list, saveignore, "ignored");
432}
433
434ignore1(list, tab, which)
435 char *list[];
436 struct ignoretab *tab;
437 char *which;
438{
eed74ec1
KS
439 char field[BUFSIZ];
440 register int h;
441 register struct ignore *igp;
442 char **ap;
443
470c33f3 444 if (*list == NOSTR)
887efe38 445 return igshow(tab, which);
eed74ec1
KS
446 for (ap = list; *ap != 0; ap++) {
447 istrcpy(field, *ap);
887efe38
EW
448 if (member(field, tab))
449 continue;
eed74ec1
KS
450 h = hash(field);
451 igp = (struct ignore *) calloc(1, sizeof (struct ignore));
828615a1
EW
452 igp->i_field = calloc((unsigned) strlen(field) + 1,
453 sizeof (char));
eed74ec1 454 strcpy(igp->i_field, field);
887efe38
EW
455 igp->i_link = tab->i_head[h];
456 tab->i_head[h] = igp;
457 tab->i_count++;
eed74ec1 458 }
887efe38 459 return 0;
eed74ec1
KS
460}
461
462/*
887efe38 463 * Print out all currently retained fields.
eed74ec1 464 */
887efe38
EW
465igshow(tab, which)
466 struct ignoretab *tab;
467 char *which;
eed74ec1 468{
887efe38 469 register int h;
eed74ec1 470 struct ignore *igp;
93be40ac
KS
471 char **ap, **ring;
472 int igcomp();
eed74ec1 473
887efe38
EW
474 if (tab->i_count == 0) {
475 printf("No fields currently being %s.\n", which);
476 return 0;
93be40ac 477 }
887efe38 478 ring = (char **) salloc((tab->i_count + 1) * sizeof (char *));
93be40ac
KS
479 ap = ring;
480 for (h = 0; h < HSHSIZE; h++)
887efe38 481 for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
93be40ac
KS
482 *ap++ = igp->i_field;
483 *ap = 0;
887efe38 484 qsort((char *) ring, tab->i_count, sizeof (char *), igcomp);
93be40ac
KS
485 for (ap = ring; *ap != 0; ap++)
486 printf("%s\n", *ap);
887efe38 487 return 0;
eed74ec1 488}
93be40ac
KS
489
490/*
491 * Compare two names for sorting ignored field list.
492 */
493igcomp(l, r)
494 char **l, **r;
495{
496
887efe38 497 return strcmp(*l, *r);
93be40ac 498}