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