Annotation of src/usr.bin/mail/cmd1.c, Revision 1.4
1.4 ! millert 1: /* $OpenBSD: cmd1.c,v 1.3 1996/06/11 12:53:32 deraadt Exp $ */
1.3 deraadt 2: /* $NetBSD: cmd1.c,v 1.5 1996/06/08 19:48:11 christos 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
39: static char sccsid[] = "@(#)cmd1.c 8.1 (Berkeley) 6/6/93";
40: #else
1.4 ! millert 41: static char rcsid[] = "$OpenBSD: cmd1.c,v 1.3 1996/06/11 12:53:32 deraadt 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) {
94: printf("No more mail.\n");
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) {
119: printf("On last screenful of messages\n");
120: return(0);
121: }
122: screen = s;
123: break;
124:
125: case '-':
126: if (--s < 0) {
127: printf("On first screenful of messages\n");
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:
149: if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0)
150: return s;
151: return screenheight - 4;
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];
188: (void) readline(setinput(mp), headline, LINESIZE);
189: if ((subjline = hfield("subject", mp)) == NOSTR)
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.4 ! millert 207: sprintf(wcount, "%3d/%-5d", mp->m_lines, mp->m_size);
1.1 deraadt 208: subjlen = screenwidth - 50 - strlen(wcount);
209: name = value("show-rcpt") != NOSTR ?
210: skin(hfield("to", mp)) : nameof(mp, 0);
211: if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */
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: {
227: printf("%d\n", dot - &message[0] + 1);
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[];
239: register const struct cmd *cp;
1.1 deraadt 240: register int cc;
241:
242: printf("Commands are:\n");
243: for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
244: cc += strlen(cp->c_name) + 2;
245: if (cc > 72) {
246: printf("\n");
247: cc = strlen(cp->c_name) + 2;
248: }
249: if ((cp+1)->c_name != NOSTR)
250: printf("%s, ", cp->c_name);
251: else
252: printf("%s\n", cp->c_name);
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.1 deraadt 265: return (type1(msgvec, 1, 1));
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:
277: return (type1(msgvec, 0, 1));
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: */
307: jmp_buf pipestop;
308: int
309: type1(msgvec, doign, page)
310: int *msgvec;
311: int doign, page;
312: {
313: register *ip;
1.3 deraadt 314: struct message *mp;
315: char *cp;
1.1 deraadt 316: int nlines;
317: FILE *obuf;
1.3 deraadt 318: #if __GNUC__
319: /* Avoid longjmp clobbering */
320: (void) &cp;
321: (void) &obuf;
322: #endif
1.1 deraadt 323:
324: obuf = stdout;
325: if (setjmp(pipestop))
326: goto close_pipe;
327: if (value("interactive") != NOSTR &&
328: (page || (cp = value("crt")) != NOSTR)) {
329: nlines = 0;
330: if (!page) {
331: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
332: nlines += message[*ip - 1].m_lines;
333: }
334: if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
335: cp = value("PAGER");
336: if (cp == NULL || *cp == '\0')
337: cp = _PATH_MORE;
338: obuf = Popen(cp, "w");
339: if (obuf == NULL) {
340: perror(cp);
341: obuf = stdout;
342: } else
343: signal(SIGPIPE, brokpipe);
344: }
345: }
346: for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
347: mp = &message[*ip - 1];
348: touch(mp);
349: dot = mp;
350: if (value("quiet") == NOSTR)
351: fprintf(obuf, "Message %d:\n", *ip);
352: (void) send(mp, obuf, doign ? ignore : 0, NOSTR);
353: }
354: close_pipe:
355: if (obuf != stdout) {
356: /*
357: * Ignore SIGPIPE so it can't cause a duplicate close.
358: */
359: signal(SIGPIPE, SIG_IGN);
360: Pclose(obuf);
361: signal(SIGPIPE, SIG_DFL);
362: }
363: return(0);
364: }
365:
366: /*
367: * Respond to a broken pipe signal --
368: * probably caused by quitting more.
369: */
370: void
371: brokpipe(signo)
372: int signo;
373: {
374: longjmp(pipestop, 1);
375: }
376:
377: /*
378: * Print the top so many lines of each desired message.
379: * The number of lines is taken from the variable "toplines"
380: * and defaults to 5.
381: */
382: int
1.3 deraadt 383: top(v)
384: void *v;
1.1 deraadt 385: {
1.3 deraadt 386: int *msgvec = v;
1.1 deraadt 387: register int *ip;
388: register struct message *mp;
389: int c, topl, lines, lineb;
390: char *valtop, linebuf[LINESIZE];
391: FILE *ibuf;
392:
393: topl = 5;
394: valtop = value("toplines");
395: if (valtop != NOSTR) {
396: topl = atoi(valtop);
397: if (topl < 0 || topl > 10000)
398: topl = 5;
399: }
400: lineb = 1;
401: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
402: mp = &message[*ip - 1];
403: touch(mp);
404: dot = mp;
405: if (value("quiet") == NOSTR)
406: printf("Message %d:\n", *ip);
407: ibuf = setinput(mp);
408: c = mp->m_lines;
409: if (!lineb)
410: printf("\n");
411: for (lines = 0; lines < c && lines <= topl; lines++) {
412: if (readline(ibuf, linebuf, LINESIZE) < 0)
413: break;
414: puts(linebuf);
415: lineb = blankline(linebuf);
416: }
417: }
418: return(0);
419: }
420:
421: /*
422: * Touch all the given messages so that they will
423: * get mboxed.
424: */
425: int
1.3 deraadt 426: stouch(v)
427: void *v;
1.1 deraadt 428: {
1.3 deraadt 429: int *msgvec = v;
1.1 deraadt 430: register int *ip;
431:
432: for (ip = msgvec; *ip != 0; ip++) {
433: dot = &message[*ip-1];
434: dot->m_flag |= MTOUCH;
435: dot->m_flag &= ~MPRESERVE;
436: }
437: return(0);
438: }
439:
440: /*
441: * Make sure all passed messages get mboxed.
442: */
443: int
1.3 deraadt 444: mboxit(v)
445: void *v;
1.1 deraadt 446: {
1.3 deraadt 447: int *msgvec = v;
1.1 deraadt 448: register int *ip;
449:
450: for (ip = msgvec; *ip != 0; ip++) {
451: dot = &message[*ip-1];
452: dot->m_flag |= MTOUCH|MBOX;
453: dot->m_flag &= ~MPRESERVE;
454: }
455: return(0);
456: }
457:
458: /*
459: * List the folders the user currently has.
460: */
461: int
1.3 deraadt 462: folders(v)
463: void *v;
1.1 deraadt 464: {
465: char dirname[BUFSIZ];
466: char *cmd;
467:
468: if (getfold(dirname) < 0) {
469: printf("No value set for \"folder\"\n");
470: return 1;
471: }
472: if ((cmd = value("LISTER")) == NOSTR)
473: cmd = "ls";
474: (void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR);
475: return 0;
476: }