1: /*-
2: * Copyright (c) 1980 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
33:
34: #if !defined(lint) && defined(DOSCCS)
35: static char sccsid[] = "@(#)cmd1.c 5.22 (Berkeley) 4/1/91";
36: #endif
37:
38: #include "rcv.h"
39:
40: /*
41: * Mail -- a mail program
42: *
43: * User commands.
44: */
45:
46: /*
47: * Print the current active headings.
48: * Don't change dot if invoker didn't give an argument.
49: */
50:
51: static int screen;
52:
53: (msgvec)
54: int *msgvec;
55: {
56: register int n, mesg, flag;
57: register struct message *mp;
58: int size;
59:
60: size = screensize();
61: n = msgvec[0];
62: if (n != 0)
63: screen = (n-1)/size;
64: if (screen < 0)
65: screen = 0;
66: mp = &message[screen * size];
67: if (mp >= &message[msgCount])
68: mp = &message[msgCount - size];
69: if (mp < &message[0])
70: mp = &message[0];
71: flag = 0;
72: mesg = mp - &message[0];
73: if (dot != &message[n-1])
74: dot = mp;
75: for (; mp < &message[msgCount]; mp++) {
76: mesg++;
77: if (mp->m_flag & MDELETED)
78: continue;
79: if (flag++ >= size)
80: break;
81: printhead(mesg);
82: }
83: if (flag == 0) {
84: printf("No more mail.\n");
85: return(1);
86: }
87: return(0);
88: }
89:
90: /*
91: * Scroll to the next/previous screen
92: */
93: scroll(arg)
94: char arg[];
95: {
96: register int s, size;
97: int cur[1];
98:
99: cur[0] = 0;
100: size = screensize();
101: s = screen;
102: switch (*arg) {
103: case 0:
104: case '+':
105: s++;
106: if (s * size > msgCount) {
107: printf("On last screenful of messages\n");
108: return(0);
109: }
110: screen = s;
111: break;
112:
113: case '-':
114: if (--s < 0) {
115: printf("On first screenful of messages\n");
116: return(0);
117: }
118: screen = s;
119: break;
120:
121: default:
122: printf("Unrecognized scrolling command \"%s\"\n", arg);
123: return(1);
124: }
125: return(headers(cur));
126: }
127:
128: /*
129: * Compute screen size.
130: */
131: screensize()
132: {
133: int s;
134: char *cp;
135:
136: if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0)
137: return s;
138: return screenheight - 4;
139: }
140:
141: /*
142: * Print out the headlines for each message
143: * in the passed message list.
144: */
145:
146: from(msgvec)
147: int *msgvec;
148: {
149: register int *ip;
150:
151: for (ip = msgvec; *ip != NULL; ip++)
152: printhead(*ip);
153: if (--ip >= msgvec)
154: dot = &message[*ip - 1];
155: return(0);
156: }
157:
158: /*
159: * Print out the header of a specific message.
160: * This is a slight improvement to the standard one.
161: */
162:
163: printhead(mesg)
164: {
165: struct message *mp;
166: char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
167: char pbuf[BUFSIZ];
168: struct headline hl;
169: int subjlen;
170: char *name;
171:
172: mp = &message[mesg-1];
173: (void) readline(setinput(mp), headline, LINESIZE);
174: if ((subjline = hfield("subject", mp)) == NOSTR)
175: subjline = hfield("subj", mp);
176: /*
177: * Bletch!
178: */
179: curind = dot == mp ? '>' : ' ';
180: dispc = ' ';
181: if (mp->m_flag & MSAVED)
182: dispc = '*';
183: if (mp->m_flag & MPRESERVE)
184: dispc = 'P';
185: if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
186: dispc = 'N';
187: if ((mp->m_flag & (MREAD|MNEW)) == 0)
188: dispc = 'U';
189: if (mp->m_flag & MBOX)
190: dispc = 'M';
191: parse(headline, &hl, pbuf);
192: sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size);
193: subjlen = screenwidth - 50 - strlen(wcount);
194: name = value("show-rcpt") != NOSTR ?
195: skin(hfield("to", mp)) : nameof(mp, 0);
196: if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */
197: printf("%c%c%3d %-20.20s %16.16s %s\n",
198: curind, dispc, mesg, name, hl.l_date, wcount);
199: else
200: printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n",
201: curind, dispc, mesg, name, hl.l_date, wcount,
202: subjlen, subjline);
203: }
204:
205: /*
206: * Print out the value of dot.
207: */
208:
209: pdot()
210: {
211: printf("%d\n", dot - &message[0] + 1);
212: return(0);
213: }
214:
215: /*
216: * Print out all the possible commands.
217: */
218:
219: pcmdlist()
220: {
221: register struct cmd *cp;
222: register int cc;
223: extern struct cmd cmdtab[];
224:
225: printf("Commands are:\n");
226: for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
227: cc += strlen(cp->c_name) + 2;
228: if (cc > 72) {
229: printf("\n");
230: cc = strlen(cp->c_name) + 2;
231: }
232: if ((cp+1)->c_name != NOSTR)
233: printf("%s, ", cp->c_name);
234: else
235: printf("%s\n", cp->c_name);
236: }
237: return(0);
238: }
239:
240: /*
241: * Paginate messages, honor ignored fields.
242: */
243: more(msgvec)
244: int *msgvec;
245: {
246: return (type1(msgvec, 1, 1));
247: }
248:
249: /*
250: * Paginate messages, even printing ignored fields.
251: */
252: More(msgvec)
253: int *msgvec;
254: {
255:
256: return (type1(msgvec, 0, 1));
257: }
258:
259: /*
260: * Type out messages, honor ignored fields.
261: */
262: type(msgvec)
263: int *msgvec;
264: {
265:
266: return(type1(msgvec, 1, 0));
267: }
268:
269: /*
270: * Type out messages, even printing ignored fields.
271: */
272: Type(msgvec)
273: int *msgvec;
274: {
275:
276: return(type1(msgvec, 0, 0));
277: }
278:
279: /*
280: * Type out the messages requested.
281: */
282: jmp_buf pipestop;
283:
284: type1(msgvec, doign, page)
285: int *msgvec;
286: {
287: register *ip;
288: register struct message *mp;
289: register char *cp;
290: int nlines;
291: FILE *obuf;
292: void brokpipe();
293:
294: obuf = stdout;
295: if (setjmp(pipestop))
296: goto close_pipe;
297: if (value("interactive") != NOSTR &&
298: (page || (cp = value("crt")) != NOSTR)) {
299: nlines = 0;
300: if (!page) {
301: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
302: nlines += message[*ip - 1].m_lines;
303: }
304: if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
305: cp = value("PAGER");
306: if (cp == NULL || *cp == '\0')
307: cp = _PATH_MORE;
308: obuf = Popen(cp, "w");
309: if (obuf == NULL) {
310: perror(cp);
311: obuf = stdout;
312: } else
313: signal(SIGPIPE, brokpipe);
314: }
315: }
316: for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
317: mp = &message[*ip - 1];
318: touch(mp);
319: dot = mp;
320: if (value("quiet") == NOSTR)
321: fprintf(obuf, "Message %d:\n", *ip);
322: (void) send(mp, obuf, doign ? ignore : 0, NOSTR);
323: }
324: close_pipe:
325: if (obuf != stdout) {
326: /*
327: * Ignore SIGPIPE so it can't cause a duplicate close.
328: */
329: signal(SIGPIPE, SIG_IGN);
330: Pclose(obuf);
331: signal(SIGPIPE, SIG_DFL);
332: }
333: return(0);
334: }
335:
336: /*
337: * Respond to a broken pipe signal --
338: * probably caused by quitting more.
339: */
340:
341: void
342: brokpipe()
343: {
344: longjmp(pipestop, 1);
345: }
346:
347: /*
348: * Print the top so many lines of each desired message.
349: * The number of lines is taken from the variable "toplines"
350: * and defaults to 5.
351: */
352:
353: top(msgvec)
354: int *msgvec;
355: {
356: register int *ip;
357: register struct message *mp;
358: int c, topl, lines, lineb;
359: char *valtop, linebuf[LINESIZE];
360: FILE *ibuf;
361:
362: topl = 5;
363: valtop = value("toplines");
364: if (valtop != NOSTR) {
365: topl = atoi(valtop);
366: if (topl < 0 || topl > 10000)
367: topl = 5;
368: }
369: lineb = 1;
370: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
371: mp = &message[*ip - 1];
372: touch(mp);
373: dot = mp;
374: if (value("quiet") == NOSTR)
375: printf("Message %d:\n", *ip);
376: ibuf = setinput(mp);
377: c = mp->m_lines;
378: if (!lineb)
379: printf("\n");
380: for (lines = 0; lines < c && lines <= topl; lines++) {
381: if (readline(ibuf, linebuf, LINESIZE) < 0)
382: break;
383: puts(linebuf);
384: lineb = blankline(linebuf);
385: }
386: }
387: return(0);
388: }
389:
390: /*
391: * Touch all the given messages so that they will
392: * get mboxed.
393: */
394: stouch(msgvec)
395: int msgvec[];
396: {
397: register int *ip;
398:
399: for (ip = msgvec; *ip != 0; ip++) {
400: dot = &message[*ip-1];
401: dot->m_flag |= MTOUCH;
402: dot->m_flag &= ~MPRESERVE;
403: }
404: return(0);
405: }
406:
407: /*
408: * Make sure all passed messages get mboxed.
409: */
410:
411: mboxit(msgvec)
412: int msgvec[];
413: {
414: register int *ip;
415:
416: for (ip = msgvec; *ip != 0; ip++) {
417: dot = &message[*ip-1];
418: dot->m_flag |= MTOUCH|MBOX;
419: dot->m_flag &= ~MPRESERVE;
420: }
421: return(0);
422: }
423:
424: /*
425: * List the folders the user currently has.
426: */
427: folders()
428: {
429: char dirname[BUFSIZ];
430: char *cmd;
431:
432: if (getfold(dirname) < 0) {
433: printf("No value set for \"folder\"\n");
434: return 1;
435: }
436: if ((cmd = value("LISTER")) == NOSTR)
437: cmd = "ls";
438: (void) run_command(cmd, 0L, -1, -1, dirname, NOSTR);
439: return 0;
440: }