xref: /original-bsd/usr.bin/mail/cmd1.c (revision f0fd5f8a)
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.9 10/21/82";
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/%ld", 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 messages, honor ignored fields.
235  */
236 type(msgvec)
237 	int *msgvec;
238 {
239 
240 	return(type1(msgvec, 1));
241 }
242 
243 /*
244  * Type out messages, even printing ignored fields.
245  */
246 Type(msgvec)
247 	int *msgvec;
248 {
249 
250 	return(type1(msgvec, 0));
251 }
252 
253 /*
254  * Type out the messages requested.
255  */
256 jmp_buf	pipestop;
257 
258 type1(msgvec, doign)
259 	int *msgvec;
260 {
261 	register *ip;
262 	register struct message *mp;
263 	register int mesg;
264 	register char *cp;
265 	int c, nlines;
266 	int brokpipe();
267 	FILE *ibuf, *obuf;
268 
269 	obuf = stdout;
270 	if (setjmp(pipestop)) {
271 		if (obuf != stdout) {
272 			pipef = NULL;
273 			pclose(obuf);
274 		}
275 		sigset(SIGPIPE, SIG_DFL);
276 		return(0);
277 	}
278 	if (intty && outtty && (cp = value("crt")) != NOSTR) {
279 		for (ip = msgvec, nlines = 0; *ip && ip-msgvec < msgCount; ip++)
280 			nlines += message[*ip - 1].m_lines;
281 		if (nlines > atoi(cp)) {
282 			obuf = popen(MORE, "w");
283 			if (obuf == NULL) {
284 				perror(MORE);
285 				obuf = stdout;
286 			}
287 			else {
288 				pipef = obuf;
289 				sigset(SIGPIPE, brokpipe);
290 			}
291 		}
292 	}
293 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
294 		mesg = *ip;
295 		touch(mesg);
296 		mp = &message[mesg-1];
297 		dot = mp;
298 		print(mp, obuf, doign);
299 	}
300 	if (obuf != stdout) {
301 		pipef = NULL;
302 		pclose(obuf);
303 	}
304 	sigset(SIGPIPE, SIG_DFL);
305 	return(0);
306 }
307 
308 /*
309  * Respond to a broken pipe signal --
310  * probably caused by using quitting more.
311  */
312 
313 brokpipe()
314 {
315 # ifdef VMUNIX
316 	sigrelse(SIGPIPE);
317 # else
318 	signal(SIGPIPE, brokpipe);
319 # endif
320 	longjmp(pipestop, 1);
321 }
322 
323 /*
324  * Print the indicated message on standard output.
325  */
326 
327 print(mp, obuf, doign)
328 	register struct message *mp;
329 	FILE *obuf;
330 {
331 
332 	if (value("quiet") == NOSTR)
333 		fprintf(obuf, "Message %2d:\n", mp - &message[0] + 1);
334 	touch(mp - &message[0] + 1);
335 	send(mp, obuf, doign);
336 }
337 
338 /*
339  * Print the top so many lines of each desired message.
340  * The number of lines is taken from the variable "toplines"
341  * and defaults to 5.
342  */
343 
344 top(msgvec)
345 	int *msgvec;
346 {
347 	register int *ip;
348 	register struct message *mp;
349 	register int mesg;
350 	int c, topl, lines, lineb;
351 	char *valtop, linebuf[LINESIZE];
352 	FILE *ibuf;
353 
354 	topl = 5;
355 	valtop = value("toplines");
356 	if (valtop != NOSTR) {
357 		topl = atoi(valtop);
358 		if (topl < 0 || topl > 10000)
359 			topl = 5;
360 	}
361 	lineb = 1;
362 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
363 		mesg = *ip;
364 		touch(mesg);
365 		mp = &message[mesg-1];
366 		dot = mp;
367 		if (value("quiet") == NOSTR)
368 			printf("Message %2d:\n", mesg);
369 		ibuf = setinput(mp);
370 		c = mp->m_lines;
371 		if (!lineb)
372 			printf("\n");
373 		for (lines = 0; lines < c && lines <= topl; lines++) {
374 			if (readline(ibuf, linebuf) <= 0)
375 				break;
376 			puts(linebuf);
377 			lineb = blankline(linebuf);
378 		}
379 	}
380 	return(0);
381 }
382 
383 /*
384  * Touch all the given messages so that they will
385  * get mboxed.
386  */
387 
388 stouch(msgvec)
389 	int msgvec[];
390 {
391 	register int *ip;
392 
393 	for (ip = msgvec; *ip != 0; ip++) {
394 		dot = &message[*ip-1];
395 		dot->m_flag |= MTOUCH;
396 		dot->m_flag &= ~MPRESERVE;
397 	}
398 	return(0);
399 }
400 
401 /*
402  * Make sure all passed messages get mboxed.
403  */
404 
405 mboxit(msgvec)
406 	int msgvec[];
407 {
408 	register int *ip;
409 
410 	for (ip = msgvec; *ip != 0; ip++) {
411 		dot = &message[*ip-1];
412 		dot->m_flag |= MTOUCH|MBOX;
413 		dot->m_flag &= ~MPRESERVE;
414 	}
415 	return(0);
416 }
417 
418 /*
419  * List the folders the user currently has.
420  */
421 folders()
422 {
423 	char dirname[BUFSIZ], cmd[BUFSIZ];
424 	int pid, s, e;
425 
426 	if (getfold(dirname) < 0) {
427 		printf("No value set for \"folder\"\n");
428 		return(-1);
429 	}
430 	switch ((pid = fork())) {
431 	case 0:
432 		sigchild();
433 		execlp("ls", "ls", dirname, 0);
434 		clrbuf(stdout);
435 		exit(1);
436 
437 	case -1:
438 		perror("fork");
439 		return(-1);
440 
441 	default:
442 		while ((e = wait(&s)) != -1 && e != pid)
443 			;
444 	}
445 	return(0);
446 }
447