Annotation of src/usr.bin/mail/cmd1.c, Revision 1.15.2.1
1.15.2.1! jason 1: /* $OpenBSD: cmd1.c,v 1.16 2000/06/30 16:00:18 millert Exp $ */
1.6 millert 2: /* $NetBSD: cmd1.c,v 1.9 1997/07/09 05:29:48 mikel Exp $ */
1.2 niklas 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.3 deraadt 38: #if 0
1.6 millert 39: static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95";
1.3 deraadt 40: #else
1.15.2.1! jason 41: static char rcsid[] = "$OpenBSD: cmd1.c,v 1.16 2000/06/30 16:00:18 millert Exp $";
1.3 deraadt 42: #endif
1.1 deraadt 43: #endif /* not lint */
44:
45: #include "rcv.h"
46: #include "extern.h"
47:
48: /*
49: * Mail -- a mail program
50: *
51: * User commands.
52: */
53:
54: /*
55: * Print the current active headings.
56: * Don't change dot if invoker didn't give an argument.
57: */
58:
59: static int screen;
60:
61: int
1.3 deraadt 62: headers(v)
63: void *v;
1.1 deraadt 64: {
1.3 deraadt 65: int *msgvec = v;
1.12 millert 66: int n, mesg, flag, size;
67: struct message *mp;
1.1 deraadt 68:
69: size = screensize();
70: n = msgvec[0];
71: if (n != 0)
72: screen = (n-1)/size;
73: if (screen < 0)
74: screen = 0;
75: mp = &message[screen * size];
76: if (mp >= &message[msgCount])
77: mp = &message[msgCount - size];
78: if (mp < &message[0])
79: mp = &message[0];
80: flag = 0;
81: mesg = mp - &message[0];
82: if (dot != &message[n-1])
83: dot = mp;
84: for (; mp < &message[msgCount]; mp++) {
85: mesg++;
86: if (mp->m_flag & MDELETED)
87: continue;
88: if (flag++ >= size)
89: break;
90: printhead(mesg);
91: }
92: if (flag == 0) {
1.6 millert 93: puts("No more mail.");
1.1 deraadt 94: return(1);
95: }
96: return(0);
97: }
98:
99: /*
100: * Scroll to the next/previous screen
101: */
102: int
1.3 deraadt 103: scroll(v)
104: void *v;
1.1 deraadt 105: {
1.3 deraadt 106: char *arg = v;
1.13 millert 107: int size, maxscreen;
1.1 deraadt 108: int cur[1];
109:
110: cur[0] = 0;
111: size = screensize();
1.13 millert 112: maxscreen = (msgCount - 1) / size;
1.1 deraadt 113: switch (*arg) {
114: case 0:
115: case '+':
1.13 millert 116: if (screen >= maxscreen) {
1.6 millert 117: puts("On last screenful of messages");
1.1 deraadt 118: return(0);
119: }
1.13 millert 120: screen++;
1.1 deraadt 121: break;
122:
123: case '-':
1.13 millert 124: if (screen <= 0) {
1.6 millert 125: puts("On first screenful of messages");
1.1 deraadt 126: return(0);
127: }
1.13 millert 128: screen--;
1.1 deraadt 129: break;
130:
131: default:
132: printf("Unrecognized scrolling command \"%s\"\n", arg);
133: return(1);
134: }
135: return(headers(cur));
136: }
137:
138: /*
139: * Compute screen size.
140: */
141: int
142: screensize()
143: {
144: int s;
145: char *cp;
146:
1.8 millert 147: if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0)
1.6 millert 148: return(s);
149: return(screenheight - 4);
1.1 deraadt 150: }
151:
152: /*
153: * Print out the headlines for each message
154: * in the passed message list.
155: */
156: int
1.3 deraadt 157: from(v)
158: void *v;
1.1 deraadt 159: {
1.3 deraadt 160: int *msgvec = v;
1.12 millert 161: int *ip;
1.1 deraadt 162:
163: for (ip = msgvec; *ip != NULL; ip++)
164: printhead(*ip);
165: if (--ip >= msgvec)
166: dot = &message[*ip - 1];
167: return(0);
168: }
169:
170: /*
171: * Print out the header of a specific message.
172: * This is a slight improvement to the standard one.
173: */
174: void
175: printhead(mesg)
176: int mesg;
177: {
178: struct message *mp;
179: char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
180: char pbuf[BUFSIZ];
181: struct headline hl;
182: int subjlen;
183: char *name;
184:
185: mp = &message[mesg-1];
1.7 millert 186: (void)readline(setinput(mp), headline, LINESIZE);
1.8 millert 187: if ((subjline = hfield("subject", mp)) == NULL)
1.1 deraadt 188: subjline = hfield("subj", mp);
189: /*
190: * Bletch!
191: */
192: curind = dot == mp ? '>' : ' ';
193: dispc = ' ';
194: if (mp->m_flag & MSAVED)
195: dispc = '*';
196: if (mp->m_flag & MPRESERVE)
197: dispc = 'P';
198: if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
199: dispc = 'N';
200: if ((mp->m_flag & (MREAD|MNEW)) == 0)
201: dispc = 'U';
202: if (mp->m_flag & MBOX)
203: dispc = 'M';
204: parse(headline, &hl, pbuf);
1.10 millert 205: (void)snprintf(wcount, sizeof(wcount), "%3d/%-5d", mp->m_lines,
206: mp->m_size);
1.1 deraadt 207: subjlen = screenwidth - 50 - strlen(wcount);
1.8 millert 208: name = value("show-rcpt") != NULL ?
1.1 deraadt 209: skin(hfield("to", mp)) : nameof(mp, 0);
1.8 millert 210: if (subjline == NULL || subjlen < 0) /* pretty pathetic */
1.1 deraadt 211: printf("%c%c%3d %-20.20s %16.16s %s\n",
212: curind, dispc, mesg, name, hl.l_date, wcount);
213: else
214: printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n",
215: curind, dispc, mesg, name, hl.l_date, wcount,
216: subjlen, subjline);
217: }
218:
219: /*
220: * Print out the value of dot.
221: */
222: int
1.3 deraadt 223: pdot(v)
224: void *v;
1.1 deraadt 225: {
1.12 millert 226: printf("%d\n", (int)(dot - &message[0] + 1));
1.1 deraadt 227: return(0);
228: }
229:
230: /*
231: * Print out all the possible commands.
232: */
233: int
1.3 deraadt 234: pcmdlist(v)
235: void *v;
1.1 deraadt 236: {
1.2 niklas 237: extern const struct cmd cmdtab[];
1.12 millert 238: const struct cmd *cp;
239: int cc;
1.1 deraadt 240:
1.6 millert 241: puts("Commands are:");
1.1 deraadt 242: for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
243: cc += strlen(cp->c_name) + 2;
244: if (cc > 72) {
1.6 millert 245: putchar('\n');
1.1 deraadt 246: cc = strlen(cp->c_name) + 2;
247: }
1.8 millert 248: if ((cp+1)->c_name != NULL)
1.1 deraadt 249: printf("%s, ", cp->c_name);
250: else
1.6 millert 251: puts(cp->c_name);
1.1 deraadt 252: }
253: return(0);
254: }
255:
256: /*
257: * Paginate messages, honor ignored fields.
258: */
259: int
1.3 deraadt 260: more(v)
261: void *v;
1.1 deraadt 262: {
1.3 deraadt 263: int *msgvec = v;
1.6 millert 264: return(type1(msgvec, 1, 1));
1.1 deraadt 265: }
266:
267: /*
268: * Paginate messages, even printing ignored fields.
269: */
270: int
1.3 deraadt 271: More(v)
272: void *v;
1.1 deraadt 273: {
1.3 deraadt 274: int *msgvec = v;
1.1 deraadt 275:
1.6 millert 276: return(type1(msgvec, 0, 1));
1.1 deraadt 277: }
278:
279: /*
280: * Type out messages, honor ignored fields.
281: */
282: int
1.3 deraadt 283: type(v)
284: void *v;
1.1 deraadt 285: {
1.3 deraadt 286: int *msgvec = v;
1.1 deraadt 287:
288: return(type1(msgvec, 1, 0));
289: }
290:
291: /*
292: * Type out messages, even printing ignored fields.
293: */
294: int
1.3 deraadt 295: Type(v)
296: void *v;
1.1 deraadt 297: {
1.3 deraadt 298: int *msgvec = v;
1.1 deraadt 299:
300: return(type1(msgvec, 0, 0));
301: }
302:
303: /*
304: * Type out the messages requested.
305: */
1.8 millert 306: sigjmp_buf pipestop;
1.1 deraadt 307: int
308: type1(msgvec, doign, page)
309: int *msgvec;
310: int doign, page;
311: {
1.12 millert 312: int nlines, *ip;
1.3 deraadt 313: struct message *mp;
314: char *cp;
1.1 deraadt 315: FILE *obuf;
1.3 deraadt 316: #if __GNUC__
1.8 millert 317: /* Avoid siglongjmp clobbering */
1.7 millert 318: (void)&cp;
319: (void)&obuf;
1.3 deraadt 320: #endif
1.1 deraadt 321:
322: obuf = stdout;
1.8 millert 323: if (sigsetjmp(pipestop, 1))
1.1 deraadt 324: goto close_pipe;
1.8 millert 325: if (value("interactive") != NULL &&
326: (page || (cp = value("crt")) != NULL)) {
1.1 deraadt 327: nlines = 0;
328: if (!page) {
329: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
330: nlines += message[*ip - 1].m_lines;
331: }
332: if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
333: cp = value("PAGER");
334: if (cp == NULL || *cp == '\0')
335: cp = _PATH_MORE;
336: obuf = Popen(cp, "w");
337: if (obuf == NULL) {
1.15.2.1! jason 338: warn("%s", cp);
1.1 deraadt 339: obuf = stdout;
340: } else
1.11 millert 341: (void)signal(SIGPIPE, brokpipe);
1.1 deraadt 342: }
343: }
344: for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
345: mp = &message[*ip - 1];
346: touch(mp);
347: dot = mp;
1.8 millert 348: if (value("quiet") == NULL)
1.1 deraadt 349: fprintf(obuf, "Message %d:\n", *ip);
1.15 millert 350: (void)sendmessage(mp, obuf, doign ? ignore : 0, NULL);
1.1 deraadt 351: }
352: close_pipe:
353: if (obuf != stdout) {
354: /*
355: * Ignore SIGPIPE so it can't cause a duplicate close.
356: */
1.11 millert 357: (void)signal(SIGPIPE, SIG_IGN);
1.6 millert 358: (void)Pclose(obuf);
1.11 millert 359: (void)signal(SIGPIPE, SIG_DFL);
1.1 deraadt 360: }
361: return(0);
362: }
363:
364: /*
365: * Respond to a broken pipe signal --
366: * probably caused by quitting more.
367: */
368: void
369: brokpipe(signo)
370: int signo;
371: {
1.8 millert 372: siglongjmp(pipestop, 1);
1.1 deraadt 373: }
374:
375: /*
376: * Print the top so many lines of each desired message.
377: * The number of lines is taken from the variable "toplines"
378: * and defaults to 5.
379: */
380: int
1.3 deraadt 381: top(v)
382: void *v;
1.1 deraadt 383: {
1.3 deraadt 384: int *msgvec = v;
1.12 millert 385: int *ip;
386: struct message *mp;
1.1 deraadt 387: int c, topl, lines, lineb;
388: char *valtop, linebuf[LINESIZE];
389: FILE *ibuf;
390:
391: topl = 5;
392: valtop = value("toplines");
1.8 millert 393: if (valtop != NULL) {
1.1 deraadt 394: topl = atoi(valtop);
395: if (topl < 0 || topl > 10000)
396: topl = 5;
397: }
398: lineb = 1;
399: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
400: mp = &message[*ip - 1];
401: touch(mp);
402: dot = mp;
1.8 millert 403: if (value("quiet") == NULL)
1.1 deraadt 404: printf("Message %d:\n", *ip);
405: ibuf = setinput(mp);
406: c = mp->m_lines;
407: if (!lineb)
1.6 millert 408: putchar('\n');
1.1 deraadt 409: for (lines = 0; lines < c && lines <= topl; lines++) {
1.9 millert 410: if (readline(ibuf, linebuf, sizeof(linebuf)) < 0)
1.1 deraadt 411: break;
412: puts(linebuf);
413: lineb = blankline(linebuf);
414: }
415: }
416: return(0);
417: }
418:
419: /*
420: * Touch all the given messages so that they will
421: * get mboxed.
422: */
423: int
1.3 deraadt 424: stouch(v)
425: void *v;
1.1 deraadt 426: {
1.3 deraadt 427: int *msgvec = v;
1.12 millert 428: int *ip;
1.1 deraadt 429:
430: for (ip = msgvec; *ip != 0; ip++) {
431: dot = &message[*ip-1];
432: dot->m_flag |= MTOUCH;
433: dot->m_flag &= ~MPRESERVE;
434: }
435: return(0);
436: }
437:
438: /*
439: * Make sure all passed messages get mboxed.
440: */
441: int
1.3 deraadt 442: mboxit(v)
443: void *v;
1.1 deraadt 444: {
1.3 deraadt 445: int *msgvec = v;
1.12 millert 446: int *ip;
1.1 deraadt 447:
448: for (ip = msgvec; *ip != 0; ip++) {
449: dot = &message[*ip-1];
450: dot->m_flag |= MTOUCH|MBOX;
451: dot->m_flag &= ~MPRESERVE;
452: }
453: return(0);
454: }
455:
456: /*
457: * List the folders the user currently has.
458: */
459: int
1.3 deraadt 460: folders(v)
461: void *v;
1.1 deraadt 462: {
1.5 deraadt 463: char dirname[PATHSIZE];
1.1 deraadt 464: char *cmd;
465:
1.6 millert 466: if (getfold(dirname, sizeof(dirname)) < 0) {
467: puts("No value set for \"folder\"");
468: return(1);
1.1 deraadt 469: }
1.8 millert 470: if ((cmd = value("LISTER")) == NULL)
1.1 deraadt 471: cmd = "ls";
1.8 millert 472: (void)run_command(cmd, 0, -1, -1, dirname, NULL, NULL);
1.6 millert 473: return(0);
474: }
475:
476: /*
477: * Update the mail file with any new messages that have
478: * come in since we started reading mail.
479: */
480: int
481: inc(v)
482: void *v;
483: {
484: int nmsg, mdot;
485:
486: nmsg = incfile();
487:
488: if (nmsg == 0) {
489: puts("No new mail.");
490: } else if (nmsg > 0) {
491: mdot = newfileinfo(msgCount - nmsg);
492: dot = &message[mdot - 1];
1.14 millert 493: clearnew();
1.6 millert 494: } else {
495: puts("\"inc\" command failed...");
496: }
497:
498: return(0);
1.1 deraadt 499: }