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