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