Annotation of src/usr.bin/mail/cmd2.c, Revision 1.19
1.19 ! gsoares 1: /* $OpenBSD: cmd2.c,v 1.18 2011/04/06 11:36:26 miod 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: #include "rcv.h"
34: #include <sys/wait.h>
35: #include "extern.h"
36:
37: /*
38: * Mail -- a mail program
39: *
40: * More user commands.
41: */
1.10 millert 42: static int igcomp(const void *, const void *);
1.1 deraadt 43:
44: /*
45: * If any arguments were given, go to the next applicable argument
46: * following dot, otherwise, go to the next applicable message.
47: * If given as first command with no arguments, print first message.
48: */
49: int
1.10 millert 50: next(void *v)
1.1 deraadt 51: {
1.8 millert 52: struct message *mp;
1.2 deraadt 53: int *msgvec = v;
1.8 millert 54: int *ip, *ip2, list[2], mdot;
1.1 deraadt 55:
1.18 miod 56: if (*msgvec != 0) {
1.1 deraadt 57: /*
1.3 millert 58: * If some messages were supplied, find the
1.1 deraadt 59: * first applicable one following dot using
60: * wrap around.
61: */
62: mdot = dot - &message[0] + 1;
63:
64: /*
65: * Find the first message in the supplied
66: * message list which follows dot.
67: */
1.18 miod 68: for (ip = msgvec; *ip != 0; ip++)
1.1 deraadt 69: if (*ip > mdot)
70: break;
1.13 avsm 71: if (*ip == 0)
1.1 deraadt 72: ip = msgvec;
73: ip2 = ip;
74: do {
75: mp = &message[*ip2 - 1];
76: if ((mp->m_flag & MDELETED) == 0) {
77: dot = mp;
78: goto hitit;
79: }
1.18 miod 80: if (*ip2 != 0)
1.1 deraadt 81: ip2++;
1.13 avsm 82: if (*ip2 == 0)
1.1 deraadt 83: ip2 = msgvec;
84: } while (ip2 != ip);
1.3 millert 85: puts("No messages applicable");
1.1 deraadt 86: return(1);
87: }
88:
89: /*
90: * If this is the first command, select message 1.
91: * Note that this must exist for us to get here at all.
92: */
93: if (!sawcom)
94: goto hitit;
95:
96: /*
97: * Just find the next good message after dot, no
98: * wraparound.
99: */
100: for (mp = dot+1; mp < &message[msgCount]; mp++)
101: if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
102: break;
103: if (mp >= &message[msgCount]) {
1.3 millert 104: puts("At EOF");
1.1 deraadt 105: return(0);
106: }
107: dot = mp;
108: hitit:
109: /*
110: * Print dot.
111: */
112: list[0] = dot - &message[0] + 1;
1.18 miod 113: list[1] = 0;
1.1 deraadt 114: return(type(list));
115: }
116:
117: /*
118: * Save a message in a file. Mark the message as saved
119: * so we can discard when the user quits.
120: */
121: int
1.10 millert 122: save(void *v)
1.1 deraadt 123: {
1.2 deraadt 124: char *str = v;
1.1 deraadt 125:
1.3 millert 126: return(save1(str, 1, "save", saveignore));
1.1 deraadt 127: }
128:
129: /*
130: * Copy a message to a file without affected its saved-ness
131: */
132: int
1.10 millert 133: copycmd(void *v)
1.1 deraadt 134: {
1.2 deraadt 135: char *str = v;
1.1 deraadt 136:
1.3 millert 137: return(save1(str, 0, "copy", saveignore));
1.1 deraadt 138: }
139:
140: /*
141: * Save/copy the indicated messages at the end of the passed file name.
142: * If mark is true, mark the message "saved."
143: */
144: int
1.10 millert 145: save1(char *str, int mark, char *cmd, struct ignoretab *ignore)
1.1 deraadt 146: {
1.8 millert 147: struct message *mp;
1.1 deraadt 148: char *file, *disp;
1.8 millert 149: int f, *msgvec, *ip;
1.1 deraadt 150: FILE *obuf;
151:
1.4 millert 152: msgvec = (int *)salloc((msgCount + 2) * sizeof(*msgvec));
1.5 millert 153: if ((file = snarf(str, &f)) == NULL)
1.1 deraadt 154: return(1);
155: if (!f) {
156: *msgvec = first(0, MMNORM);
1.13 avsm 157: if (*msgvec == 0) {
1.1 deraadt 158: printf("No messages to %s.\n", cmd);
159: return(1);
160: }
1.18 miod 161: msgvec[1] = 0;
1.1 deraadt 162: }
163: if (f && getmsglist(str, msgvec, 0) < 0)
164: return(1);
1.5 millert 165: if ((file = expand(file)) == NULL)
1.1 deraadt 166: return(1);
167: printf("\"%s\" ", file);
168: fflush(stdout);
1.19 ! gsoares 169: if (access(file, F_OK) >= 0)
1.1 deraadt 170: disp = "[Appended]";
171: else
172: disp = "[New file]";
173: if ((obuf = Fopen(file, "a")) == NULL) {
1.5 millert 174: warn(NULL);
1.1 deraadt 175: return(1);
176: }
177: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
178: mp = &message[*ip - 1];
179: touch(mp);
1.9 millert 180: if (sendmessage(mp, obuf, ignore, NULL) < 0) {
1.8 millert 181: warn("%s", file);
1.3 millert 182: (void)Fclose(obuf);
1.1 deraadt 183: return(1);
184: }
185: if (mark)
186: mp->m_flag |= MSAVED;
187: }
188: fflush(obuf);
189: if (ferror(obuf))
1.8 millert 190: warn("%s", file);
1.3 millert 191: (void)Fclose(obuf);
1.1 deraadt 192: printf("%s\n", disp);
193: return(0);
194: }
195:
196: /*
197: * Write the indicated messages at the end of the passed
198: * file name, minus header and trailing blank line.
199: */
200: int
1.10 millert 201: swrite(void *v)
1.1 deraadt 202: {
1.2 deraadt 203: char *str = v;
1.1 deraadt 204:
1.3 millert 205: return(save1(str, 1, "write", ignoreall));
1.1 deraadt 206: }
207:
208: /*
209: * Snarf the file from the end of the command line and
210: * return a pointer to it. If there is no file attached,
1.5 millert 211: * just return NULL. Put a null in front of the file
1.1 deraadt 212: * name so that the message list processing won't see it,
213: * unless the file name is the only thing on the line, in
214: * which case, return 0 in the reference flag variable.
215: */
216: char *
1.10 millert 217: snarf(char *linebuf, int *flag)
1.1 deraadt 218: {
1.8 millert 219: char *cp;
1.1 deraadt 220:
221: *flag = 1;
222: cp = strlen(linebuf) + linebuf - 1;
223:
224: /*
225: * Strip away trailing blanks.
226: */
227: while (cp > linebuf && isspace(*cp))
228: cp--;
229: *++cp = 0;
230:
231: /*
232: * Now search for the beginning of the file name.
233: */
234: while (cp > linebuf && !isspace(*cp))
235: cp--;
236: if (*cp == '\0') {
1.3 millert 237: puts("No file specified.");
1.5 millert 238: return(NULL);
1.1 deraadt 239: }
240: if (isspace(*cp))
241: *cp++ = 0;
242: else
243: *flag = 0;
244: return(cp);
245: }
246:
247: /*
248: * Delete messages.
249: */
250: int
1.15 deraadt 251: deletecmd(void *v)
1.1 deraadt 252: {
1.2 deraadt 253: int *msgvec = v;
1.10 millert 254:
1.1 deraadt 255: delm(msgvec);
1.3 millert 256: return(0);
1.1 deraadt 257: }
258:
259: /*
260: * Delete messages, then type the new dot.
261: */
262: int
1.10 millert 263: deltype(void *v)
1.1 deraadt 264: {
1.2 deraadt 265: int *msgvec = v;
1.1 deraadt 266: int list[2];
267: int lastdot;
268:
269: lastdot = dot - &message[0] + 1;
270: if (delm(msgvec) >= 0) {
271: list[0] = dot - &message[0] + 1;
272: if (list[0] > lastdot) {
273: touch(dot);
1.18 miod 274: list[1] = 0;
1.1 deraadt 275: return(type(list));
276: }
1.3 millert 277: puts("At EOF");
1.1 deraadt 278: } else
1.3 millert 279: puts("No more messages");
1.1 deraadt 280: return(0);
281: }
282:
283: /*
284: * Delete the indicated messages.
285: * Set dot to some nice place afterwards.
286: * Internal interface.
287: */
288: int
1.10 millert 289: delm(int *msgvec)
1.1 deraadt 290: {
1.8 millert 291: struct message *mp;
292: int *ip, last;
1.1 deraadt 293:
1.18 miod 294: last = 0;
295: for (ip = msgvec; *ip != 0; ip++) {
1.1 deraadt 296: mp = &message[*ip - 1];
297: touch(mp);
298: mp->m_flag |= MDELETED|MTOUCH;
299: mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
300: last = *ip;
301: }
1.18 miod 302: if (last != 0) {
1.1 deraadt 303: dot = &message[last-1];
304: last = first(0, MDELETED);
1.18 miod 305: if (last != 0) {
1.1 deraadt 306: dot = &message[last-1];
307: return(0);
308: }
309: else {
310: dot = &message[0];
311: return(-1);
312: }
313: }
314:
315: /*
316: * Following can't happen -- it keeps lint happy
317: */
318: return(-1);
319: }
320:
321: /*
322: * Undelete the indicated messages.
323: */
324: int
1.10 millert 325: undeletecmd(void *v)
1.1 deraadt 326: {
1.2 deraadt 327: int *msgvec = v;
1.8 millert 328: int *ip;
329: struct message *mp;
1.1 deraadt 330:
331: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
332: mp = &message[*ip - 1];
333: touch(mp);
334: dot = mp;
335: mp->m_flag &= ~MDELETED;
336: }
1.3 millert 337: return(0);
1.1 deraadt 338: }
339:
340: /*
341: * Add the given header fields to the retained list.
342: * If no arguments, print the current list of retained fields.
343: */
344: int
1.10 millert 345: retfield(void *v)
1.1 deraadt 346: {
1.2 deraadt 347: char **list = v;
1.1 deraadt 348:
1.3 millert 349: return(ignore1(list, ignore + 1, "retained"));
1.1 deraadt 350: }
351:
352: /*
353: * Add the given header fields to the ignored list.
354: * If no arguments, print the current list of ignored fields.
355: */
356: int
1.10 millert 357: igfield(void *v)
1.1 deraadt 358: {
1.2 deraadt 359: char **list = v;
1.1 deraadt 360:
1.3 millert 361: return(ignore1(list, ignore, "ignored"));
1.1 deraadt 362: }
363:
364: int
1.10 millert 365: saveretfield(void *v)
1.1 deraadt 366: {
1.2 deraadt 367: char **list = v;
1.1 deraadt 368:
1.3 millert 369: return(ignore1(list, saveignore + 1, "retained"));
1.1 deraadt 370: }
371:
372: int
1.10 millert 373: saveigfield(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, "ignored"));
1.1 deraadt 378: }
379:
380: int
1.10 millert 381: ignore1(char **list, struct ignoretab *tab, char *which)
1.1 deraadt 382: {
1.3 millert 383: char field[LINESIZE];
1.1 deraadt 384: char **ap;
1.8 millert 385: struct ignore *igp;
386: int h;
1.1 deraadt 387:
1.5 millert 388: if (*list == NULL)
1.3 millert 389: return(igshow(tab, which));
1.1 deraadt 390: for (ap = list; *ap != 0; ap++) {
1.10 millert 391: istrlcpy(field, *ap, sizeof(field));
1.1 deraadt 392: if (member(field, tab))
393: continue;
394: h = hash(field);
1.4 millert 395: igp = (struct ignore *)calloc(1, sizeof(struct ignore));
1.11 millert 396: if (igp == NULL)
397: errx(1, "Out of memory");
398: igp->i_field = strdup(field);
399: if (igp->i_field == NULL)
400: errx(1, "Out of memory");
1.1 deraadt 401: igp->i_link = tab->i_head[h];
402: tab->i_head[h] = igp;
403: tab->i_count++;
404: }
1.3 millert 405: return(0);
1.1 deraadt 406: }
407:
408: /*
409: * Print out all currently retained fields.
410: */
411: int
1.10 millert 412: igshow(struct ignoretab *tab, char *which)
1.1 deraadt 413: {
1.8 millert 414: int h;
1.1 deraadt 415: struct ignore *igp;
416: char **ap, **ring;
417:
418: if (tab->i_count == 0) {
419: printf("No fields currently being %s.\n", which);
1.3 millert 420: return(0);
1.1 deraadt 421: }
1.4 millert 422: ring = (char **)salloc((tab->i_count + 1) * sizeof(char *));
1.1 deraadt 423: ap = ring;
424: for (h = 0; h < HSHSIZE; h++)
425: for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
426: *ap++ = igp->i_field;
427: *ap = 0;
1.3 millert 428: qsort(ring, tab->i_count, sizeof(char *), igcomp);
1.1 deraadt 429: for (ap = ring; *ap != 0; ap++)
1.3 millert 430: puts(*ap);
431: return(0);
1.1 deraadt 432: }
433:
434: /*
435: * Compare two names for sorting ignored field list.
436: */
1.2 deraadt 437: static int
1.10 millert 438: igcomp(const void *l, const void *r)
1.1 deraadt 439: {
1.10 millert 440:
1.3 millert 441: return(strcmp(*(char **)l, *(char **)r));
1.1 deraadt 442: }