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