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