xref: /original-bsd/usr.bin/mail/cmd1.c (revision 76571ef5)
1 #
2 #include "rcv.h"
3 #include <sys/stat.h>
4 
5 /*
6  * Mail -- a mail program
7  *
8  * User commands.
9  */
10 
11 static char *SccsId = "@(#)cmd1.c	2.3 12/10/81";
12 
13 /*
14  * Print the current active headings.
15  * Don't change dot if invoker didn't give an argument.
16  */
17 
18 static int screen;
19 
20 headers(msgvec)
21 	int *msgvec;
22 {
23 	register int n, mesg, flag;
24 	register struct message *mp;
25 	int size;
26 
27 	size = screensize();
28 	n = msgvec[0];
29 	if (n != 0)
30 		screen = (n-1)/size;
31 	if (screen < 0)
32 		screen = 0;
33 	mp = &message[screen * size];
34 	if (mp >= &message[msgCount])
35 		mp = &message[msgCount - size];
36 	if (mp < &message[0])
37 		mp = &message[0];
38 	flag = 0;
39 	mesg = mp - &message[0];
40 	if (dot != &message[n-1])
41 		dot = mp;
42 	for (; mp < &message[msgCount]; mp++) {
43 		mesg++;
44 		if (mp->m_flag & MDELETED)
45 			continue;
46 		if (flag++ >= size)
47 			break;
48 		printhead(mesg);
49 		sreset();
50 	}
51 	if (flag == 0) {
52 		printf("No more mail.\n");
53 		return(1);
54 	}
55 	return(0);
56 }
57 
58 /*
59  * Scroll to the next/previous screen
60  */
61 
62 scroll(arg)
63 	char arg[];
64 {
65 	register int s, size;
66 	int cur[1];
67 
68 	cur[0] = 0;
69 	size = screensize();
70 	s = screen;
71 	switch (*arg) {
72 	case 0:
73 	case '+':
74 		s++;
75 		if (s * size > msgCount) {
76 			printf("On last screenful of messages\n");
77 			return(0);
78 		}
79 		screen = s;
80 		break;
81 
82 	case '-':
83 		if (--s < 0) {
84 			printf("On first screenful of messages\n");
85 			return(0);
86 		}
87 		screen = s;
88 		break;
89 
90 	default:
91 		printf("Unrecognized scrolling command \"%s\"\n", arg);
92 		return(1);
93 	}
94 	return(headers(cur));
95 }
96 
97 /*
98  * Compute what the screen size should be.
99  * We use the following algorithm:
100  *	If user specifies with screen option, use that.
101  *	If baud rate < 1200, use  5
102  *	If baud rate = 1200, use 10
103  *	If baud rate > 1200, use 20
104  */
105 screensize()
106 {
107 	register char *cp;
108 	register int s;
109 
110 	if ((cp = value("screen")) != NOSTR) {
111 		s = atoi(cp);
112 		if (s > 0)
113 			return(s);
114 	}
115 	if (baud < B1200)
116 		s = 5;
117 	else if (baud == B1200)
118 		s = 10;
119 	else
120 		s = 20;
121 	return(s);
122 }
123 
124 /*
125  * Print out the headlines for each message
126  * in the passed message list.
127  */
128 
129 from(msgvec)
130 	int *msgvec;
131 {
132 	register int *ip;
133 
134 	for (ip = msgvec; *ip != NULL; ip++) {
135 		printhead(*ip);
136 		sreset();
137 	}
138 	if (--ip >= msgvec)
139 		dot = &message[*ip - 1];
140 	return(0);
141 }
142 
143 /*
144  * Print out the header of a specific message.
145  * This is a slight improvement to the standard one.
146  */
147 
148 printhead(mesg)
149 {
150 	struct message *mp;
151 	FILE *ibuf;
152 	char headline[LINESIZE], wcount[10], *subjline, dispc, curind;
153 	char pbuf[BUFSIZ];
154 	int s;
155 	struct headline hl;
156 	register char *cp;
157 
158 	mp = &message[mesg-1];
159 	ibuf = setinput(mp);
160 	readline(ibuf, headline);
161 	subjline = hfield("subject", mp);
162 	if (subjline == NOSTR)
163 		subjline = hfield("subj", mp);
164 
165 	/*
166 	 * Bletch!
167 	 */
168 
169 	if (subjline != NOSTR && strlen(subjline) > 28)
170 		subjline[29] = '\0';
171 	curind = dot == mp ? '>' : ' ';
172 	dispc = ' ';
173 	if (mp->m_flag & MSAVED)
174 		dispc = '*';
175 	if (mp->m_flag & MPRESERVE)
176 		dispc = 'P';
177 	if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
178 		dispc = 'N';
179 	if ((mp->m_flag & (MREAD|MNEW)) == 0)
180 		dispc = 'U';
181 	if (mp->m_flag & MBOX)
182 		dispc = 'M';
183 	parse(headline, &hl, pbuf);
184 	sprintf(wcount, " %d/%d", mp->m_lines, mp->m_size);
185 	s = strlen(wcount);
186 	cp = wcount + s;
187 	while (s < 7)
188 		s++, *cp++ = ' ';
189 	*cp = '\0';
190 	if (subjline != NOSTR)
191 		printf("%c%c%3d %-8s %16.16s %s \"%s\"\n", curind, dispc, mesg,
192 		    nameof(mp, 0), hl.l_date, wcount, subjline);
193 	else
194 		printf("%c%c%3d %-8s %16.16s %s\n", curind, dispc, mesg,
195 		    nameof(mp, 0), hl.l_date, wcount);
196 }
197 
198 /*
199  * Print out the value of dot.
200  */
201 
202 pdot()
203 {
204 	printf("%d\n", dot - &message[0] + 1);
205 	return(0);
206 }
207 
208 /*
209  * Print out all the possible commands.
210  */
211 
212 pcmdlist()
213 {
214 	register struct cmd *cp;
215 	register int cc;
216 	extern struct cmd cmdtab[];
217 
218 	printf("Commands are:\n");
219 	for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
220 		cc += strlen(cp->c_name) + 2;
221 		if (cc > 72) {
222 			printf("\n");
223 			cc = strlen(cp->c_name) + 2;
224 		}
225 		if ((cp+1)->c_name != NOSTR)
226 			printf("%s, ", cp->c_name);
227 		else
228 			printf("%s\n", cp->c_name);
229 	}
230 	return(0);
231 }
232 
233 /*
234  * Type out the messages requested.
235  */
236 
237 jmp_buf	pipestop;
238 
239 type(msgvec)
240 	int *msgvec;
241 {
242 	register *ip;
243 	register struct message *mp;
244 	register int mesg;
245 	register char *cp;
246 	int c, nlines;
247 	int brokpipe();
248 	FILE *ibuf, *obuf;
249 
250 	obuf = stdout;
251 	if (setjmp(pipestop)) {
252 		if (obuf != stdout) {
253 			pipef = NULL;
254 			pclose(obuf);
255 		}
256 		sigset(SIGPIPE, SIG_DFL);
257 		return(0);
258 	}
259 	if (intty && outtty && (cp = value("crt")) != NOSTR) {
260 		for (ip = msgvec, nlines = 0; *ip && ip-msgvec < msgCount; ip++)
261 			nlines += message[*ip - 1].m_lines;
262 		if (nlines > atoi(cp)) {
263 			obuf = popen(MORE, "w");
264 			if (obuf == NULL) {
265 				perror(MORE);
266 				obuf = stdout;
267 			}
268 			else {
269 				pipef = obuf;
270 				sigset(SIGPIPE, brokpipe);
271 			}
272 		}
273 	}
274 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
275 		mesg = *ip;
276 		touch(mesg);
277 		mp = &message[mesg-1];
278 		dot = mp;
279 		print(mp, obuf);
280 	}
281 	if (obuf != stdout) {
282 		pipef = NULL;
283 		pclose(obuf);
284 	}
285 	sigset(SIGPIPE, SIG_DFL);
286 	return(0);
287 }
288 
289 /*
290  * Respond to a broken pipe signal --
291  * probably caused by using quitting more.
292  */
293 
294 brokpipe()
295 {
296 
297 	sigrelse(SIGPIPE);
298 	longjmp(pipestop, 1);
299 }
300 
301 /*
302  * Print the indicated message on standard output.
303  */
304 
305 print(mp, obuf)
306 	register struct message *mp;
307 	FILE *obuf;
308 {
309 
310 	if (value("quiet") == NOSTR)
311 		fprintf(obuf, "Message %2d:\n", mp - &message[0] + 1);
312 	touch(mp - &message[0] + 1);
313 	send(mp, obuf);
314 }
315 
316 /*
317  * Print the top so many lines of each desired message.
318  * The number of lines is taken from the variable "toplines"
319  * and defaults to 5.
320  */
321 
322 top(msgvec)
323 	int *msgvec;
324 {
325 	register int *ip;
326 	register struct message *mp;
327 	register int mesg;
328 	int c, topl, lines, lineb;
329 	char *valtop, linebuf[LINESIZE];
330 	FILE *ibuf;
331 
332 	topl = 5;
333 	valtop = value("toplines");
334 	if (valtop != NOSTR) {
335 		topl = atoi(valtop);
336 		if (topl < 0 || topl > 10000)
337 			topl = 5;
338 	}
339 	lineb = 1;
340 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
341 		mesg = *ip;
342 		touch(mesg);
343 		mp = &message[mesg-1];
344 		dot = mp;
345 		if (value("quiet") == NOSTR)
346 			printf("Message %2d:\n", mesg);
347 		ibuf = setinput(mp);
348 		c = mp->m_lines;
349 		if (!lineb)
350 			printf("\n");
351 		for (lines = 0; lines < c && lines <= topl; lines++) {
352 			if (readline(ibuf, linebuf) <= 0)
353 				break;
354 			puts(linebuf);
355 			lineb = blankline(linebuf);
356 		}
357 	}
358 	return(0);
359 }
360 
361 /*
362  * Touch all the given messages so that they will
363  * get mboxed.
364  */
365 
366 stouch(msgvec)
367 	int msgvec[];
368 {
369 	register int *ip;
370 
371 	for (ip = msgvec; *ip != 0; ip++) {
372 		dot = &message[*ip-1];
373 		dot->m_flag |= MTOUCH;
374 		dot->m_flag &= ~MPRESERVE;
375 	}
376 	return(0);
377 }
378 
379 /*
380  * Make sure all passed messages get mboxed.
381  */
382 
383 mboxit(msgvec)
384 	int msgvec[];
385 {
386 	register int *ip;
387 
388 	for (ip = msgvec; *ip != 0; ip++) {
389 		dot = &message[*ip-1];
390 		dot->m_flag |= MTOUCH|MBOX;
391 		dot->m_flag &= ~MPRESERVE;
392 	}
393 	return(0);
394 }
395