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