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