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