xref: /freebsd/usr.bin/mail/cmd1.c (revision b7a1a0a5ff8895e6a5c9404d02357ac9e2eb8091)
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
35 static 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 
52 static int screen;
53 
54 int
55 headers(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  */
95 int
96 scroll(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  */
134 int
135 screensize()
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  */
149 int
150 from(msgvec)
151 	int *msgvec;
152 {
153 	register int *ip;
154 
155 	for (ip = msgvec; *ip != NULL; 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  */
166 void
167 printhead(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  */
213 int
214 pdot()
215 {
216 	printf("%d\n", dot - &message[0] + 1);
217 	return(0);
218 }
219 
220 /*
221  * Print out all the possible commands.
222  */
223 int
224 pcmdlist()
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  */
248 int
249 more(msgvec)
250 	int *msgvec;
251 {
252 	return (type1(msgvec, 1, 1));
253 }
254 
255 /*
256  * Paginate messages, even printing ignored fields.
257  */
258 int
259 More(msgvec)
260 	int *msgvec;
261 {
262 
263 	return (type1(msgvec, 0, 1));
264 }
265 
266 /*
267  * Type out messages, honor ignored fields.
268  */
269 int
270 type(msgvec)
271 	int *msgvec;
272 {
273 
274 	return(type1(msgvec, 1, 0));
275 }
276 
277 /*
278  * Type out messages, even printing ignored fields.
279  */
280 int
281 Type(msgvec)
282 	int *msgvec;
283 {
284 
285 	return(type1(msgvec, 0, 0));
286 }
287 
288 /*
289  * Type out the messages requested.
290  */
291 jmp_buf	pipestop;
292 int
293 type1(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 	}
333 close_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  */
349 void
350 brokpipe(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  */
361 int
362 top(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  */
403 int
404 stouch(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  */
420 int
421 mboxit(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  */
437 int
438 folders()
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