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