Annotation of src/usr.bin/mail/cmd2.c, Revision 1.16
1.16 ! martynas 1: /* $OpenBSD: cmd2.c,v 1.15 2004/09/15 22:21:40 deraadt 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.16 ! martynas 37: static const char rcsid[] = "$OpenBSD: cmd2.c,v 1.15 2004/09/15 22:21:40 deraadt 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;
1.13 avsm 79: if (*ip == 0)
1.1 deraadt 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++;
1.13 avsm 90: if (*ip2 == 0)
1.1 deraadt 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);
1.13 avsm 165: if (*msgvec == 0) {
1.1 deraadt 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.15 deraadt 259: deletecmd(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: * Add the given header fields to the retained list.
350: * If no arguments, print the current list of retained fields.
351: */
352: int
1.10 millert 353: retfield(void *v)
1.1 deraadt 354: {
1.2 deraadt 355: char **list = v;
1.1 deraadt 356:
1.3 millert 357: return(ignore1(list, ignore + 1, "retained"));
1.1 deraadt 358: }
359:
360: /*
361: * Add the given header fields to the ignored list.
362: * If no arguments, print the current list of ignored fields.
363: */
364: int
1.10 millert 365: igfield(void *v)
1.1 deraadt 366: {
1.2 deraadt 367: char **list = v;
1.1 deraadt 368:
1.3 millert 369: return(ignore1(list, ignore, "ignored"));
1.1 deraadt 370: }
371:
372: int
1.10 millert 373: saveretfield(void *v)
1.1 deraadt 374: {
1.2 deraadt 375: char **list = v;
1.1 deraadt 376:
1.3 millert 377: return(ignore1(list, saveignore + 1, "retained"));
1.1 deraadt 378: }
379:
380: int
1.10 millert 381: saveigfield(void *v)
1.1 deraadt 382: {
1.2 deraadt 383: char **list = v;
1.1 deraadt 384:
1.3 millert 385: return(ignore1(list, saveignore, "ignored"));
1.1 deraadt 386: }
387:
388: int
1.10 millert 389: ignore1(char **list, struct ignoretab *tab, char *which)
1.1 deraadt 390: {
1.3 millert 391: char field[LINESIZE];
1.1 deraadt 392: char **ap;
1.8 millert 393: struct ignore *igp;
394: int h;
1.1 deraadt 395:
1.5 millert 396: if (*list == NULL)
1.3 millert 397: return(igshow(tab, which));
1.1 deraadt 398: for (ap = list; *ap != 0; ap++) {
1.10 millert 399: istrlcpy(field, *ap, sizeof(field));
1.1 deraadt 400: if (member(field, tab))
401: continue;
402: h = hash(field);
1.4 millert 403: igp = (struct ignore *)calloc(1, sizeof(struct ignore));
1.11 millert 404: if (igp == NULL)
405: errx(1, "Out of memory");
406: igp->i_field = strdup(field);
407: if (igp->i_field == NULL)
408: errx(1, "Out of memory");
1.1 deraadt 409: igp->i_link = tab->i_head[h];
410: tab->i_head[h] = igp;
411: tab->i_count++;
412: }
1.3 millert 413: return(0);
1.1 deraadt 414: }
415:
416: /*
417: * Print out all currently retained fields.
418: */
419: int
1.10 millert 420: igshow(struct ignoretab *tab, char *which)
1.1 deraadt 421: {
1.8 millert 422: int h;
1.1 deraadt 423: struct ignore *igp;
424: char **ap, **ring;
425:
426: if (tab->i_count == 0) {
427: printf("No fields currently being %s.\n", which);
1.3 millert 428: return(0);
1.1 deraadt 429: }
1.4 millert 430: ring = (char **)salloc((tab->i_count + 1) * sizeof(char *));
1.1 deraadt 431: ap = ring;
432: for (h = 0; h < HSHSIZE; h++)
433: for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
434: *ap++ = igp->i_field;
435: *ap = 0;
1.3 millert 436: qsort(ring, tab->i_count, sizeof(char *), igcomp);
1.1 deraadt 437: for (ap = ring; *ap != 0; ap++)
1.3 millert 438: puts(*ap);
439: return(0);
1.1 deraadt 440: }
441:
442: /*
443: * Compare two names for sorting ignored field list.
444: */
1.2 deraadt 445: static int
1.10 millert 446: igcomp(const void *l, const void *r)
1.1 deraadt 447: {
1.10 millert 448:
1.3 millert 449: return(strcmp(*(char **)l, *(char **)r));
1.1 deraadt 450: }