Annotation of src/usr.bin/mail/cmd2.c, Revision 1.9
1.9 ! millert 1: /* $OpenBSD: cmd2.c,v 1.8 1997/11/14 00:23:43 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
39: static char sccsid[] = "@(#)cmd2.c 8.1 (Berkeley) 6/6/93";
40: #else
1.9 ! millert 41: static char rcsid[] = "$OpenBSD: cmd2.c,v 1.8 1997/11/14 00:23:43 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.2 deraadt 54: static int igcomp __P((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.2 deraadt 62: next(v)
63: void *v;
1.1 deraadt 64: {
1.8 millert 65: struct message *mp;
1.2 deraadt 66: int *msgvec = v;
1.8 millert 67: int *ip, *ip2, list[2], mdot;
1.1 deraadt 68:
69: if (*msgvec != NULL) {
70:
71: /*
1.3 millert 72: * If some messages were supplied, find the
1.1 deraadt 73: * first applicable one following dot using
74: * wrap around.
75: */
76:
77: mdot = dot - &message[0] + 1;
78:
79: /*
80: * Find the first message in the supplied
81: * message list which follows dot.
82: */
83:
84: for (ip = msgvec; *ip != NULL; ip++)
85: if (*ip > mdot)
86: break;
87: if (*ip == NULL)
88: ip = msgvec;
89: ip2 = ip;
90: do {
91: mp = &message[*ip2 - 1];
92: if ((mp->m_flag & MDELETED) == 0) {
93: dot = mp;
94: goto hitit;
95: }
96: if (*ip2 != NULL)
97: ip2++;
98: if (*ip2 == NULL)
99: ip2 = msgvec;
100: } while (ip2 != ip);
1.3 millert 101: puts("No messages applicable");
1.1 deraadt 102: return(1);
103: }
104:
105: /*
106: * If this is the first command, select message 1.
107: * Note that this must exist for us to get here at all.
108: */
109:
110: if (!sawcom)
111: goto hitit;
112:
113: /*
114: * Just find the next good message after dot, no
115: * wraparound.
116: */
117:
118: for (mp = dot+1; mp < &message[msgCount]; mp++)
119: if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
120: break;
121: if (mp >= &message[msgCount]) {
1.3 millert 122: puts("At EOF");
1.1 deraadt 123: return(0);
124: }
125: dot = mp;
126: hitit:
127: /*
128: * Print dot.
129: */
130:
131: list[0] = dot - &message[0] + 1;
132: list[1] = NULL;
133: return(type(list));
134: }
135:
136: /*
137: * Save a message in a file. Mark the message as saved
138: * so we can discard when the user quits.
139: */
140: int
1.2 deraadt 141: save(v)
142: void *v;
1.1 deraadt 143: {
1.2 deraadt 144: char *str = v;
1.1 deraadt 145:
1.3 millert 146: return(save1(str, 1, "save", saveignore));
1.1 deraadt 147: }
148:
149: /*
150: * Copy a message to a file without affected its saved-ness
151: */
152: int
1.2 deraadt 153: copycmd(v)
154: void *v;
1.1 deraadt 155: {
1.2 deraadt 156: char *str = v;
1.1 deraadt 157:
1.3 millert 158: return(save1(str, 0, "copy", saveignore));
1.1 deraadt 159: }
160:
161: /*
162: * Save/copy the indicated messages at the end of the passed file name.
163: * If mark is true, mark the message "saved."
164: */
165: int
166: save1(str, mark, cmd, ignore)
167: char str[];
168: int mark;
169: char *cmd;
170: struct ignoretab *ignore;
171: {
1.8 millert 172: struct message *mp;
1.1 deraadt 173: char *file, *disp;
1.8 millert 174: int f, *msgvec, *ip;
1.1 deraadt 175: FILE *obuf;
176:
1.4 millert 177: msgvec = (int *)salloc((msgCount + 2) * sizeof(*msgvec));
1.5 millert 178: if ((file = snarf(str, &f)) == NULL)
1.1 deraadt 179: return(1);
180: if (!f) {
181: *msgvec = first(0, MMNORM);
182: if (*msgvec == NULL) {
183: printf("No messages to %s.\n", cmd);
184: return(1);
185: }
186: msgvec[1] = NULL;
187: }
188: if (f && getmsglist(str, msgvec, 0) < 0)
189: return(1);
1.5 millert 190: if ((file = expand(file)) == NULL)
1.1 deraadt 191: return(1);
192: printf("\"%s\" ", file);
193: fflush(stdout);
194: if (access(file, 0) >= 0)
195: disp = "[Appended]";
196: else
197: disp = "[New file]";
198: if ((obuf = Fopen(file, "a")) == NULL) {
1.5 millert 199: warn(NULL);
1.1 deraadt 200: return(1);
201: }
202: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
203: mp = &message[*ip - 1];
204: touch(mp);
1.9 ! millert 205: if (sendmessage(mp, obuf, ignore, NULL) < 0) {
1.8 millert 206: warn("%s", file);
1.3 millert 207: (void)Fclose(obuf);
1.1 deraadt 208: return(1);
209: }
210: if (mark)
211: mp->m_flag |= MSAVED;
212: }
213: fflush(obuf);
214: if (ferror(obuf))
1.8 millert 215: warn("%s", file);
1.3 millert 216: (void)Fclose(obuf);
1.1 deraadt 217: printf("%s\n", disp);
218: return(0);
219: }
220:
221: /*
222: * Write the indicated messages at the end of the passed
223: * file name, minus header and trailing blank line.
224: */
225: int
1.2 deraadt 226: swrite(v)
227: void *v;
1.1 deraadt 228: {
1.2 deraadt 229: char *str = v;
1.1 deraadt 230:
1.3 millert 231: return(save1(str, 1, "write", ignoreall));
1.1 deraadt 232: }
233:
234: /*
235: * Snarf the file from the end of the command line and
236: * return a pointer to it. If there is no file attached,
1.5 millert 237: * just return NULL. Put a null in front of the file
1.1 deraadt 238: * name so that the message list processing won't see it,
239: * unless the file name is the only thing on the line, in
240: * which case, return 0 in the reference flag variable.
241: */
242:
243: char *
244: snarf(linebuf, flag)
245: char linebuf[];
246: int *flag;
247: {
1.8 millert 248: char *cp;
1.1 deraadt 249:
250: *flag = 1;
251: cp = strlen(linebuf) + linebuf - 1;
252:
253: /*
254: * Strip away trailing blanks.
255: */
256:
257: while (cp > linebuf && isspace(*cp))
258: cp--;
259: *++cp = 0;
260:
261: /*
262: * Now search for the beginning of the file name.
263: */
264:
265: while (cp > linebuf && !isspace(*cp))
266: cp--;
267: if (*cp == '\0') {
1.3 millert 268: puts("No file specified.");
1.5 millert 269: return(NULL);
1.1 deraadt 270: }
271: if (isspace(*cp))
272: *cp++ = 0;
273: else
274: *flag = 0;
275: return(cp);
276: }
277:
278: /*
279: * Delete messages.
280: */
281: int
1.2 deraadt 282: delete(v)
283: void *v;
1.1 deraadt 284: {
1.2 deraadt 285: int *msgvec = v;
1.1 deraadt 286: delm(msgvec);
1.3 millert 287: return(0);
1.1 deraadt 288: }
289:
290: /*
291: * Delete messages, then type the new dot.
292: */
293: int
1.2 deraadt 294: deltype(v)
295: void *v;
1.1 deraadt 296: {
1.2 deraadt 297: int *msgvec = v;
1.1 deraadt 298: int list[2];
299: int lastdot;
300:
301: lastdot = dot - &message[0] + 1;
302: if (delm(msgvec) >= 0) {
303: list[0] = dot - &message[0] + 1;
304: if (list[0] > lastdot) {
305: touch(dot);
306: list[1] = NULL;
307: return(type(list));
308: }
1.3 millert 309: puts("At EOF");
1.1 deraadt 310: } else
1.3 millert 311: puts("No more messages");
1.1 deraadt 312: return(0);
313: }
314:
315: /*
316: * Delete the indicated messages.
317: * Set dot to some nice place afterwards.
318: * Internal interface.
319: */
320: int
321: delm(msgvec)
322: int *msgvec;
323: {
1.8 millert 324: struct message *mp;
325: int *ip, last;
1.1 deraadt 326:
327: last = NULL;
328: for (ip = msgvec; *ip != NULL; ip++) {
329: mp = &message[*ip - 1];
330: touch(mp);
331: mp->m_flag |= MDELETED|MTOUCH;
332: mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
333: last = *ip;
334: }
335: if (last != NULL) {
336: dot = &message[last-1];
337: last = first(0, MDELETED);
338: if (last != NULL) {
339: dot = &message[last-1];
340: return(0);
341: }
342: else {
343: dot = &message[0];
344: return(-1);
345: }
346: }
347:
348: /*
349: * Following can't happen -- it keeps lint happy
350: */
351:
352: return(-1);
353: }
354:
355: /*
356: * Undelete the indicated messages.
357: */
358: int
1.2 deraadt 359: undeletecmd(v)
360: void *v;
1.1 deraadt 361: {
1.2 deraadt 362: int *msgvec = v;
1.8 millert 363: int *ip;
364: struct message *mp;
1.1 deraadt 365:
366: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
367: mp = &message[*ip - 1];
368: touch(mp);
369: dot = mp;
370: mp->m_flag &= ~MDELETED;
371: }
1.3 millert 372: return(0);
1.1 deraadt 373: }
374:
375: /*
376: * Interactively dump core on "core"
377: */
378: int
1.2 deraadt 379: core(v)
380: void *v;
1.1 deraadt 381: {
382: int pid;
1.7 millert 383: extern int wait_status;
1.1 deraadt 384:
385: switch (pid = vfork()) {
386: case -1:
1.8 millert 387: warn("vfork");
1.1 deraadt 388: return(1);
389: case 0:
390: abort();
391: _exit(1);
392: }
1.3 millert 393: fputs("Okie dokie", stdout);
1.1 deraadt 394: fflush(stdout);
395: wait_child(pid);
1.7 millert 396: if (WIFSIGNALED(wait_status) && WCOREDUMP(wait_status))
1.3 millert 397: puts(" -- Core dumped.");
1.1 deraadt 398: else
1.3 millert 399: puts(" -- Can't dump core.");
400: return(0);
1.1 deraadt 401: }
402:
403: /*
404: * Clobber as many bytes of stack as the user requests.
405: */
406: int
1.2 deraadt 407: clobber(v)
408: void *v;
1.1 deraadt 409: {
1.2 deraadt 410: char **argv = v;
1.8 millert 411: int times;
1.1 deraadt 412:
413: if (argv[0] == 0)
414: times = 1;
415: else
416: times = (atoi(argv[0]) + 511) / 512;
417: clob1(times);
1.3 millert 418: return(0);
1.1 deraadt 419: }
420:
421: /*
422: * Clobber the stack.
423: */
424: void
425: clob1(n)
426: int n;
427: {
428: char buf[512];
1.8 millert 429: char *cp;
1.1 deraadt 430:
431: if (n <= 0)
432: return;
433: for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
434: ;
435: clob1(n - 1);
436: }
437:
438: /*
439: * Add the given header fields to the retained list.
440: * If no arguments, print the current list of retained fields.
441: */
442: int
1.2 deraadt 443: retfield(v)
444: void *v;
1.1 deraadt 445: {
1.2 deraadt 446: char **list = v;
1.1 deraadt 447:
1.3 millert 448: return(ignore1(list, ignore + 1, "retained"));
1.1 deraadt 449: }
450:
451: /*
452: * Add the given header fields to the ignored list.
453: * If no arguments, print the current list of ignored fields.
454: */
455: int
1.2 deraadt 456: igfield(v)
457: void *v;
1.1 deraadt 458: {
1.2 deraadt 459: char **list = v;
1.1 deraadt 460:
1.3 millert 461: return(ignore1(list, ignore, "ignored"));
1.1 deraadt 462: }
463:
464: int
1.2 deraadt 465: saveretfield(v)
466: void *v;
1.1 deraadt 467: {
1.2 deraadt 468: char **list = v;
1.1 deraadt 469:
1.3 millert 470: return(ignore1(list, saveignore + 1, "retained"));
1.1 deraadt 471: }
472:
473: int
1.2 deraadt 474: saveigfield(v)
475: void *v;
1.1 deraadt 476: {
1.2 deraadt 477: char **list = v;
1.1 deraadt 478:
1.3 millert 479: return(ignore1(list, saveignore, "ignored"));
1.1 deraadt 480: }
481:
482: int
483: ignore1(list, tab, which)
484: char *list[];
485: struct ignoretab *tab;
486: char *which;
487: {
1.3 millert 488: char field[LINESIZE];
1.1 deraadt 489: char **ap;
1.8 millert 490: struct ignore *igp;
491: int h;
1.1 deraadt 492:
1.5 millert 493: if (*list == NULL)
1.3 millert 494: return(igshow(tab, which));
1.1 deraadt 495: for (ap = list; *ap != 0; ap++) {
1.6 millert 496: istrncpy(field, *ap, sizeof(field));
1.1 deraadt 497: if (member(field, tab))
498: continue;
499: h = hash(field);
1.4 millert 500: igp = (struct ignore *)calloc(1, sizeof(struct ignore));
501: igp->i_field = (char *)calloc(strlen(field) + 1, sizeof(char));
1.1 deraadt 502: strcpy(igp->i_field, field);
503: igp->i_link = tab->i_head[h];
504: tab->i_head[h] = igp;
505: tab->i_count++;
506: }
1.3 millert 507: return(0);
1.1 deraadt 508: }
509:
510: /*
511: * Print out all currently retained fields.
512: */
513: int
514: igshow(tab, which)
515: struct ignoretab *tab;
516: char *which;
517: {
1.8 millert 518: int h;
1.1 deraadt 519: struct ignore *igp;
520: char **ap, **ring;
521:
522: if (tab->i_count == 0) {
523: printf("No fields currently being %s.\n", which);
1.3 millert 524: return(0);
1.1 deraadt 525: }
1.4 millert 526: ring = (char **)salloc((tab->i_count + 1) * sizeof(char *));
1.1 deraadt 527: ap = ring;
528: for (h = 0; h < HSHSIZE; h++)
529: for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
530: *ap++ = igp->i_field;
531: *ap = 0;
1.3 millert 532: qsort(ring, tab->i_count, sizeof(char *), igcomp);
1.1 deraadt 533: for (ap = ring; *ap != 0; ap++)
1.3 millert 534: puts(*ap);
535: return(0);
1.1 deraadt 536: }
537:
538: /*
539: * Compare two names for sorting ignored field list.
540: */
1.2 deraadt 541: static int
1.1 deraadt 542: igcomp(l, r)
543: const void *l, *r;
544: {
1.3 millert 545: return(strcmp(*(char **)l, *(char **)r));
1.1 deraadt 546: }