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