xref: /netbsd-src/usr.bin/mail/cmd1.c (revision ce63d6c20fc4ec8ddc95c84bb229e3c4ecf82b69)
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[] = "@(#)cmd1.c	5.22 (Berkeley) 4/1/91";
36 #endif /* not lint */
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 headers(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, 0, -1, -1, dirname, NOSTR);
439 	return 0;
440 }
441