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