Annotation of src/usr.bin/mail/cmd2.c, Revision 1.11
1.11 ! millert 1: /* $OpenBSD: cmd2.c,v 1.10 2001/11/21 15:26:39 millert Exp $ */
1.3 millert 2: /* $NetBSD: cmd2.c,v 1.7 1997/05/17 19:55:10 pk Exp $ */
1.2 deraadt 3:
1.1 deraadt 4: /*
5: * Copyright (c) 1980, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
1.2 deraadt 38: #if 0
1.10 millert 39: static const char sccsid[] = "@(#)cmd2.c 8.1 (Berkeley) 6/6/93";
1.2 deraadt 40: #else
1.11 ! millert 41: static const char rcsid[] = "$OpenBSD: cmd2.c,v 1.10 2001/11/21 15:26:39 millert Exp $";
1.2 deraadt 42: #endif
1.1 deraadt 43: #endif /* not lint */
44:
45: #include "rcv.h"
46: #include <sys/wait.h>
47: #include "extern.h"
48:
49: /*
50: * Mail -- a mail program
51: *
52: * More user commands.
53: */
1.10 millert 54: static int igcomp(const void *, const void *);
1.1 deraadt 55:
56: /*
57: * If any arguments were given, go to the next applicable argument
58: * following dot, otherwise, go to the next applicable message.
59: * If given as first command with no arguments, print first message.
60: */
61: int
1.10 millert 62: next(void *v)
1.1 deraadt 63: {
1.8 millert 64: struct message *mp;
1.2 deraadt 65: int *msgvec = v;
1.8 millert 66: int *ip, *ip2, list[2], mdot;
1.1 deraadt 67:
68: if (*msgvec != NULL) {
69: /*
1.3 millert 70: * If some messages were supplied, find the
1.1 deraadt 71: * first applicable one following dot using
72: * wrap around.
73: */
74: mdot = dot - &message[0] + 1;
75:
76: /*
77: * Find the first message in the supplied
78: * message list which follows dot.
79: */
80: for (ip = msgvec; *ip != NULL; ip++)
81: if (*ip > mdot)
82: break;
83: if (*ip == NULL)
84: ip = msgvec;
85: ip2 = ip;
86: do {
87: mp = &message[*ip2 - 1];
88: if ((mp->m_flag & MDELETED) == 0) {
89: dot = mp;
90: goto hitit;
91: }
92: if (*ip2 != NULL)
93: ip2++;
94: if (*ip2 == NULL)
95: ip2 = msgvec;
96: } while (ip2 != ip);
1.3 millert 97: puts("No messages applicable");
1.1 deraadt 98: return(1);
99: }
100:
101: /*
102: * If this is the first command, select message 1.
103: * Note that this must exist for us to get here at all.
104: */
105: if (!sawcom)
106: goto hitit;
107:
108: /*
109: * Just find the next good message after dot, no
110: * wraparound.
111: */
112: for (mp = dot+1; mp < &message[msgCount]; mp++)
113: if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
114: break;
115: if (mp >= &message[msgCount]) {
1.3 millert 116: puts("At EOF");
1.1 deraadt 117: return(0);
118: }
119: dot = mp;
120: hitit:
121: /*
122: * Print dot.
123: */
124: list[0] = dot - &message[0] + 1;
125: list[1] = NULL;
126: return(type(list));
127: }
128:
129: /*
130: * Save a message in a file. Mark the message as saved
131: * so we can discard when the user quits.
132: */
133: int
1.10 millert 134: save(void *v)
1.1 deraadt 135: {
1.2 deraadt 136: char *str = v;
1.1 deraadt 137:
1.3 millert 138: return(save1(str, 1, "save", saveignore));
1.1 deraadt 139: }
140:
141: /*
142: * Copy a message to a file without affected its saved-ness
143: */
144: int
1.10 millert 145: copycmd(void *v)
1.1 deraadt 146: {
1.2 deraadt 147: char *str = v;
1.1 deraadt 148:
1.3 millert 149: return(save1(str, 0, "copy", saveignore));
1.1 deraadt 150: }
151:
152: /*
153: * Save/copy the indicated messages at the end of the passed file name.
154: * If mark is true, mark the message "saved."
155: */
156: int
1.10 millert 157: save1(char *str, int mark, char *cmd, struct ignoretab *ignore)
1.1 deraadt 158: {
1.8 millert 159: struct message *mp;
1.1 deraadt 160: char *file, *disp;
1.8 millert 161: int f, *msgvec, *ip;
1.1 deraadt 162: FILE *obuf;
163:
1.4 millert 164: msgvec = (int *)salloc((msgCount + 2) * sizeof(*msgvec));
1.5 millert 165: if ((file = snarf(str, &f)) == NULL)
1.1 deraadt 166: return(1);
167: if (!f) {
168: *msgvec = first(0, MMNORM);
169: if (*msgvec == NULL) {
170: printf("No messages to %s.\n", cmd);
171: return(1);
172: }
173: msgvec[1] = NULL;
174: }
175: if (f && getmsglist(str, msgvec, 0) < 0)
176: return(1);
1.5 millert 177: if ((file = expand(file)) == NULL)
1.1 deraadt 178: return(1);
179: printf("\"%s\" ", file);
180: fflush(stdout);
181: if (access(file, 0) >= 0)
182: disp = "[Appended]";
183: else
184: disp = "[New file]";
185: if ((obuf = Fopen(file, "a")) == NULL) {
1.5 millert 186: warn(NULL);
1.1 deraadt 187: return(1);
188: }
189: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
190: mp = &message[*ip - 1];
191: touch(mp);
1.9 millert 192: if (sendmessage(mp, obuf, ignore, NULL) < 0) {
1.8 millert 193: warn("%s", file);
1.3 millert 194: (void)Fclose(obuf);
1.1 deraadt 195: return(1);
196: }
197: if (mark)
198: mp->m_flag |= MSAVED;
199: }
200: fflush(obuf);
201: if (ferror(obuf))
1.8 millert 202: warn("%s", file);
1.3 millert 203: (void)Fclose(obuf);
1.1 deraadt 204: printf("%s\n", disp);
205: return(0);
206: }
207:
208: /*
209: * Write the indicated messages at the end of the passed
210: * file name, minus header and trailing blank line.
211: */
212: int
1.10 millert 213: swrite(void *v)
1.1 deraadt 214: {
1.2 deraadt 215: char *str = v;
1.1 deraadt 216:
1.3 millert 217: return(save1(str, 1, "write", ignoreall));
1.1 deraadt 218: }
219:
220: /*
221: * Snarf the file from the end of the command line and
222: * return a pointer to it. If there is no file attached,
1.5 millert 223: * just return NULL. Put a null in front of the file
1.1 deraadt 224: * name so that the message list processing won't see it,
225: * unless the file name is the only thing on the line, in
226: * which case, return 0 in the reference flag variable.
227: */
228: char *
1.10 millert 229: snarf(char *linebuf, int *flag)
1.1 deraadt 230: {
1.8 millert 231: char *cp;
1.1 deraadt 232:
233: *flag = 1;
234: cp = strlen(linebuf) + linebuf - 1;
235:
236: /*
237: * Strip away trailing blanks.
238: */
239: while (cp > linebuf && isspace(*cp))
240: cp--;
241: *++cp = 0;
242:
243: /*
244: * Now search for the beginning of the file name.
245: */
246: while (cp > linebuf && !isspace(*cp))
247: cp--;
248: if (*cp == '\0') {
1.3 millert 249: puts("No file specified.");
1.5 millert 250: return(NULL);
1.1 deraadt 251: }
252: if (isspace(*cp))
253: *cp++ = 0;
254: else
255: *flag = 0;
256: return(cp);
257: }
258:
259: /*
260: * Delete messages.
261: */
262: int
1.10 millert 263: delete(void *v)
1.1 deraadt 264: {
1.2 deraadt 265: int *msgvec = v;
1.10 millert 266:
1.1 deraadt 267: delm(msgvec);
1.3 millert 268: return(0);
1.1 deraadt 269: }
270:
271: /*
272: * Delete messages, then type the new dot.
273: */
274: int
1.10 millert 275: deltype(void *v)
1.1 deraadt 276: {
1.2 deraadt 277: int *msgvec = v;
1.1 deraadt 278: int list[2];
279: int lastdot;
280:
281: lastdot = dot - &message[0] + 1;
282: if (delm(msgvec) >= 0) {
283: list[0] = dot - &message[0] + 1;
284: if (list[0] > lastdot) {
285: touch(dot);
286: list[1] = NULL;
287: return(type(list));
288: }
1.3 millert 289: puts("At EOF");
1.1 deraadt 290: } else
1.3 millert 291: puts("No more messages");
1.1 deraadt 292: return(0);
293: }
294:
295: /*
296: * Delete the indicated messages.
297: * Set dot to some nice place afterwards.
298: * Internal interface.
299: */
300: int
1.10 millert 301: delm(int *msgvec)
1.1 deraadt 302: {
1.8 millert 303: struct message *mp;
304: int *ip, last;
1.1 deraadt 305:
306: last = NULL;
307: for (ip = msgvec; *ip != NULL; ip++) {
308: mp = &message[*ip - 1];
309: touch(mp);
310: mp->m_flag |= MDELETED|MTOUCH;
311: mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
312: last = *ip;
313: }
314: if (last != NULL) {
315: dot = &message[last-1];
316: last = first(0, MDELETED);
317: if (last != NULL) {
318: dot = &message[last-1];
319: return(0);
320: }
321: else {
322: dot = &message[0];
323: return(-1);
324: }
325: }
326:
327: /*
328: * Following can't happen -- it keeps lint happy
329: */
330: return(-1);
331: }
332:
333: /*
334: * Undelete the indicated messages.
335: */
336: int
1.10 millert 337: undeletecmd(void *v)
1.1 deraadt 338: {
1.2 deraadt 339: int *msgvec = v;
1.8 millert 340: int *ip;
341: struct message *mp;
1.1 deraadt 342:
343: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
344: mp = &message[*ip - 1];
345: touch(mp);
346: dot = mp;
347: mp->m_flag &= ~MDELETED;
348: }
1.3 millert 349: return(0);
1.1 deraadt 350: }
351:
352: /*
353: * Interactively dump core on "core"
354: */
355: int
1.10 millert 356: core(void *v)
1.1 deraadt 357: {
1.10 millert 358: pid_t pid;
1.7 millert 359: extern int wait_status;
1.1 deraadt 360:
361: switch (pid = vfork()) {
362: case -1:
1.8 millert 363: warn("vfork");
1.1 deraadt 364: return(1);
365: case 0:
366: abort();
367: _exit(1);
368: }
1.3 millert 369: fputs("Okie dokie", stdout);
1.1 deraadt 370: fflush(stdout);
371: wait_child(pid);
1.7 millert 372: if (WIFSIGNALED(wait_status) && WCOREDUMP(wait_status))
1.3 millert 373: puts(" -- Core dumped.");
1.1 deraadt 374: else
1.3 millert 375: puts(" -- Can't dump core.");
376: return(0);
1.1 deraadt 377: }
378:
379: /*
380: * Clobber as many bytes of stack as the user requests.
381: */
382: int
1.10 millert 383: clobber(void *v)
1.1 deraadt 384: {
1.2 deraadt 385: char **argv = v;
1.8 millert 386: int times;
1.1 deraadt 387:
388: if (argv[0] == 0)
389: times = 1;
390: else
391: times = (atoi(argv[0]) + 511) / 512;
392: clob1(times);
1.3 millert 393: return(0);
1.1 deraadt 394: }
395:
396: /*
397: * Clobber the stack.
398: */
399: void
400: clob1(n)
401: int n;
402: {
403: char buf[512];
1.8 millert 404: char *cp;
1.1 deraadt 405:
406: if (n <= 0)
407: return;
408: for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
409: ;
410: clob1(n - 1);
411: }
412:
413: /*
414: * Add the given header fields to the retained list.
415: * If no arguments, print the current list of retained fields.
416: */
417: int
1.10 millert 418: retfield(void *v)
1.1 deraadt 419: {
1.2 deraadt 420: char **list = v;
1.1 deraadt 421:
1.3 millert 422: return(ignore1(list, ignore + 1, "retained"));
1.1 deraadt 423: }
424:
425: /*
426: * Add the given header fields to the ignored list.
427: * If no arguments, print the current list of ignored fields.
428: */
429: int
1.10 millert 430: igfield(void *v)
1.1 deraadt 431: {
1.2 deraadt 432: char **list = v;
1.1 deraadt 433:
1.3 millert 434: return(ignore1(list, ignore, "ignored"));
1.1 deraadt 435: }
436:
437: int
1.10 millert 438: saveretfield(void *v)
1.1 deraadt 439: {
1.2 deraadt 440: char **list = v;
1.1 deraadt 441:
1.3 millert 442: return(ignore1(list, saveignore + 1, "retained"));
1.1 deraadt 443: }
444:
445: int
1.10 millert 446: saveigfield(void *v)
1.1 deraadt 447: {
1.2 deraadt 448: char **list = v;
1.1 deraadt 449:
1.3 millert 450: return(ignore1(list, saveignore, "ignored"));
1.1 deraadt 451: }
452:
453: int
1.10 millert 454: ignore1(char **list, struct ignoretab *tab, char *which)
1.1 deraadt 455: {
1.3 millert 456: char field[LINESIZE];
1.1 deraadt 457: char **ap;
1.8 millert 458: struct ignore *igp;
459: int h;
1.1 deraadt 460:
1.5 millert 461: if (*list == NULL)
1.3 millert 462: return(igshow(tab, which));
1.1 deraadt 463: for (ap = list; *ap != 0; ap++) {
1.10 millert 464: istrlcpy(field, *ap, sizeof(field));
1.1 deraadt 465: if (member(field, tab))
466: continue;
467: h = hash(field);
1.4 millert 468: igp = (struct ignore *)calloc(1, sizeof(struct ignore));
1.11 ! millert 469: if (igp == NULL)
! 470: errx(1, "Out of memory");
! 471: igp->i_field = strdup(field);
! 472: if (igp->i_field == NULL)
! 473: errx(1, "Out of memory");
1.1 deraadt 474: igp->i_link = tab->i_head[h];
475: tab->i_head[h] = igp;
476: tab->i_count++;
477: }
1.3 millert 478: return(0);
1.1 deraadt 479: }
480:
481: /*
482: * Print out all currently retained fields.
483: */
484: int
1.10 millert 485: igshow(struct ignoretab *tab, char *which)
1.1 deraadt 486: {
1.8 millert 487: int h;
1.1 deraadt 488: struct ignore *igp;
489: char **ap, **ring;
490:
491: if (tab->i_count == 0) {
492: printf("No fields currently being %s.\n", which);
1.3 millert 493: return(0);
1.1 deraadt 494: }
1.4 millert 495: ring = (char **)salloc((tab->i_count + 1) * sizeof(char *));
1.1 deraadt 496: ap = ring;
497: for (h = 0; h < HSHSIZE; h++)
498: for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
499: *ap++ = igp->i_field;
500: *ap = 0;
1.3 millert 501: qsort(ring, tab->i_count, sizeof(char *), igcomp);
1.1 deraadt 502: for (ap = ring; *ap != 0; ap++)
1.3 millert 503: puts(*ap);
504: return(0);
1.1 deraadt 505: }
506:
507: /*
508: * Compare two names for sorting ignored field list.
509: */
1.2 deraadt 510: static int
1.10 millert 511: igcomp(const void *l, const void *r)
1.1 deraadt 512: {
1.10 millert 513:
1.3 millert 514: return(strcmp(*(char **)l, *(char **)r));
1.1 deraadt 515: }