added "more" command
[unix-history] / usr / src / usr.bin / mail / cmd1.c
CommitLineData
2ae9f53f 1#ifndef lint
b041ccec 2static char sccsid[] = "@(#)cmd1.c 2.14 (Berkeley) %G%";
2ae9f53f
SL
3#endif
4
d702437a
KS
5#include "rcv.h"
6#include <sys/stat.h>
7
8/*
9 * Mail -- a mail program
10 *
11 * User commands.
12 */
13
d702437a
KS
14/*
15 * Print the current active headings.
f75dd1e5 16 * Don't change dot if invoker didn't give an argument.
d702437a
KS
17 */
18
19static int screen;
20
21headers(msgvec)
22 int *msgvec;
23{
24 register int n, mesg, flag;
25 register struct message *mp;
1491ef97 26 int size;
d702437a 27
1491ef97 28 size = screensize();
d702437a
KS
29 n = msgvec[0];
30 if (n != 0)
1491ef97 31 screen = (n-1)/size;
d702437a
KS
32 if (screen < 0)
33 screen = 0;
1491ef97 34 mp = &message[screen * size];
d702437a 35 if (mp >= &message[msgCount])
1491ef97 36 mp = &message[msgCount - size];
d702437a
KS
37 if (mp < &message[0])
38 mp = &message[0];
39 flag = 0;
40 mesg = mp - &message[0];
f75dd1e5
KS
41 if (dot != &message[n-1])
42 dot = mp;
d702437a
KS
43 for (; mp < &message[msgCount]; mp++) {
44 mesg++;
45 if (mp->m_flag & MDELETED)
46 continue;
1491ef97 47 if (flag++ >= size)
d702437a
KS
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
06440f31
CL
59/*
60 * Set the list of alternate names for out host.
61 */
62local(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
d702437a
KS
89/*
90 * Scroll to the next/previous screen
91 */
92
93scroll(arg)
94 char arg[];
95{
1491ef97 96 register int s, size;
d702437a
KS
97 int cur[1];
98
99 cur[0] = 0;
1491ef97 100 size = screensize();
d702437a
KS
101 s = screen;
102 switch (*arg) {
103 case 0:
104 case '+':
105 s++;
1491ef97 106 if (s * size > msgCount) {
d702437a
KS
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
1491ef97
KS
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 */
136screensize()
137{
138 register char *cp;
139 register int s;
b041ccec
S
140#ifdef TIOCGWINSZ
141 struct winsize ws;
142#endif
1491ef97
KS
143
144 if ((cp = value("screen")) != NOSTR) {
145 s = atoi(cp);
146 if (s > 0)
147 return(s);
148 }
149 if (baud < B1200)
150 s = 5;
151 else if (baud == B1200)
152 s = 10;
b041ccec
S
153#ifdef TIOCGWINSZ
154 else if (ioctl(fileno(stdout), TIOCGWINSZ, &ws) == 0 && ws.ws_row != 0)
155 s = ws.ws_row - 4;
156#endif
1491ef97
KS
157 else
158 s = 20;
159 return(s);
160}
d702437a
KS
161
162/*
163 * Print out the headlines for each message
164 * in the passed message list.
165 */
166
167from(msgvec)
168 int *msgvec;
169{
170 register int *ip;
171
172 for (ip = msgvec; *ip != NULL; ip++) {
173 printhead(*ip);
174 sreset();
175 }
176 if (--ip >= msgvec)
177 dot = &message[*ip - 1];
178 return(0);
179}
180
181/*
182 * Print out the header of a specific message.
183 * This is a slight improvement to the standard one.
184 */
185
186printhead(mesg)
187{
188 struct message *mp;
189 FILE *ibuf;
f75dd1e5 190 char headline[LINESIZE], wcount[10], *subjline, dispc, curind;
d702437a
KS
191 char pbuf[BUFSIZ];
192 int s;
193 struct headline hl;
194 register char *cp;
195
196 mp = &message[mesg-1];
197 ibuf = setinput(mp);
198 readline(ibuf, headline);
199 subjline = hfield("subject", mp);
200 if (subjline == NOSTR)
201 subjline = hfield("subj", mp);
202
203 /*
204 * Bletch!
205 */
206
207 if (subjline != NOSTR && strlen(subjline) > 28)
208 subjline[29] = '\0';
f75dd1e5 209 curind = dot == mp ? '>' : ' ';
d702437a
KS
210 dispc = ' ';
211 if (mp->m_flag & MSAVED)
212 dispc = '*';
213 if (mp->m_flag & MPRESERVE)
214 dispc = 'P';
5bfbbe88 215 if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
f4d36a07 216 dispc = 'N';
5bfbbe88
KS
217 if ((mp->m_flag & (MREAD|MNEW)) == 0)
218 dispc = 'U';
f2230dfd
KS
219 if (mp->m_flag & MBOX)
220 dispc = 'M';
d702437a 221 parse(headline, &hl, pbuf);
0154300b 222 sprintf(wcount, " %d/%ld", mp->m_lines, mp->m_size);
d702437a
KS
223 s = strlen(wcount);
224 cp = wcount + s;
225 while (s < 7)
226 s++, *cp++ = ' ';
227 *cp = '\0';
228 if (subjline != NOSTR)
f75dd1e5 229 printf("%c%c%3d %-8s %16.16s %s \"%s\"\n", curind, dispc, mesg,
186f16d8 230 nameof(mp, 0), hl.l_date, wcount, subjline);
d702437a 231 else
f75dd1e5 232 printf("%c%c%3d %-8s %16.16s %s\n", curind, dispc, mesg,
186f16d8 233 nameof(mp, 0), hl.l_date, wcount);
d702437a
KS
234}
235
236/*
237 * Print out the value of dot.
238 */
239
240pdot()
241{
242 printf("%d\n", dot - &message[0] + 1);
243 return(0);
244}
245
246/*
247 * Print out all the possible commands.
248 */
249
250pcmdlist()
251{
252 register struct cmd *cp;
253 register int cc;
254 extern struct cmd cmdtab[];
255
256 printf("Commands are:\n");
257 for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
258 cc += strlen(cp->c_name) + 2;
259 if (cc > 72) {
260 printf("\n");
261 cc = strlen(cp->c_name) + 2;
262 }
263 if ((cp+1)->c_name != NOSTR)
264 printf("%s, ", cp->c_name);
265 else
266 printf("%s\n", cp->c_name);
267 }
268 return(0);
269}
270
b041ccec
S
271/*
272 * Paginate messages, honor ignored fields.
273 */
274more(msgvec)
275 int *msgvec;
276{
277 return (type1(msgvec, 1, 1));
278}
279
280/*
281 * Paginate messages, even printing ignored fields.
282 */
283More(msgvec)
284 int *msgvec;
285{
286
287 return (type1(msgvec, 0, 1));
288}
289
d702437a 290/*
15bff4bb 291 * Type out messages, honor ignored fields.
d702437a 292 */
15bff4bb
KS
293type(msgvec)
294 int *msgvec;
295{
d702437a 296
b041ccec 297 return(type1(msgvec, 1, 0));
15bff4bb
KS
298}
299
300/*
301 * Type out messages, even printing ignored fields.
302 */
303Type(msgvec)
304 int *msgvec;
305{
306
b041ccec 307 return(type1(msgvec, 0, 0));
15bff4bb
KS
308}
309
310/*
311 * Type out the messages requested.
312 */
740867ff
KS
313jmp_buf pipestop;
314
b041ccec 315type1(msgvec, doign, page)
d702437a
KS
316 int *msgvec;
317{
318 register *ip;
319 register struct message *mp;
320 register int mesg;
740867ff
KS
321 register char *cp;
322 int c, nlines;
323 int brokpipe();
324 FILE *ibuf, *obuf;
325
326 obuf = stdout;
327 if (setjmp(pipestop)) {
328 if (obuf != stdout) {
740867ff 329 pipef = NULL;
fc3f7633 330 pclose(obuf);
740867ff 331 }
fd0ddf32 332 sigset(SIGPIPE, SIG_DFL);
740867ff
KS
333 return(0);
334 }
b041ccec
S
335 if (intty && outtty && (page || (cp = value("crt")) != NOSTR)) {
336 if (!page) {
337 nlines = 0;
338 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
339 nlines += message[*ip - 1].m_lines;
340 }
341 if (page || nlines > atoi(cp)) {
740867ff
KS
342 obuf = popen(MORE, "w");
343 if (obuf == NULL) {
344 perror(MORE);
345 obuf = stdout;
346 }
347 else {
348 pipef = obuf;
fd0ddf32 349 sigset(SIGPIPE, brokpipe);
740867ff
KS
350 }
351 }
352 }
d702437a
KS
353 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
354 mesg = *ip;
355 touch(mesg);
356 mp = &message[mesg-1];
357 dot = mp;
15bff4bb 358 print(mp, obuf, doign);
740867ff 359 }
740867ff 360 if (obuf != stdout) {
740867ff 361 pipef = NULL;
fc3f7633 362 pclose(obuf);
d702437a 363 }
fd0ddf32 364 sigset(SIGPIPE, SIG_DFL);
d702437a
KS
365 return(0);
366}
367
740867ff
KS
368/*
369 * Respond to a broken pipe signal --
370 * probably caused by using quitting more.
371 */
372
373brokpipe()
374{
4bc721c3 375# ifndef VMUNIX
ea394d88
KS
376 signal(SIGPIPE, brokpipe);
377# endif
fc3f7633 378 longjmp(pipestop, 1);
740867ff
KS
379}
380
d702437a
KS
381/*
382 * Print the indicated message on standard output.
383 */
384
15bff4bb 385print(mp, obuf, doign)
d702437a 386 register struct message *mp;
740867ff 387 FILE *obuf;
d702437a
KS
388{
389
390 if (value("quiet") == NOSTR)
740867ff 391 fprintf(obuf, "Message %2d:\n", mp - &message[0] + 1);
d702437a 392 touch(mp - &message[0] + 1);
15bff4bb 393 send(mp, obuf, doign);
d702437a
KS
394}
395
396/*
397 * Print the top so many lines of each desired message.
398 * The number of lines is taken from the variable "toplines"
399 * and defaults to 5.
400 */
401
402top(msgvec)
403 int *msgvec;
404{
405 register int *ip;
406 register struct message *mp;
407 register int mesg;
408 int c, topl, lines, lineb;
409 char *valtop, linebuf[LINESIZE];
410 FILE *ibuf;
411
412 topl = 5;
413 valtop = value("toplines");
414 if (valtop != NOSTR) {
415 topl = atoi(valtop);
416 if (topl < 0 || topl > 10000)
417 topl = 5;
418 }
419 lineb = 1;
420 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
421 mesg = *ip;
422 touch(mesg);
423 mp = &message[mesg-1];
424 dot = mp;
425 if (value("quiet") == NOSTR)
426 printf("Message %2d:\n", mesg);
427 ibuf = setinput(mp);
428 c = mp->m_lines;
429 if (!lineb)
430 printf("\n");
431 for (lines = 0; lines < c && lines <= topl; lines++) {
432 if (readline(ibuf, linebuf) <= 0)
433 break;
434 puts(linebuf);
435 lineb = blankline(linebuf);
436 }
437 }
438 return(0);
439}
440
441/*
442 * Touch all the given messages so that they will
443 * get mboxed.
444 */
445
446stouch(msgvec)
447 int msgvec[];
448{
449 register int *ip;
450
451 for (ip = msgvec; *ip != 0; ip++) {
d702437a 452 dot = &message[*ip-1];
5bfbbe88 453 dot->m_flag |= MTOUCH;
d702437a
KS
454 dot->m_flag &= ~MPRESERVE;
455 }
456 return(0);
457}
f2230dfd
KS
458
459/*
460 * Make sure all passed messages get mboxed.
461 */
462
463mboxit(msgvec)
464 int msgvec[];
465{
466 register int *ip;
467
468 for (ip = msgvec; *ip != 0; ip++) {
469 dot = &message[*ip-1];
470 dot->m_flag |= MTOUCH|MBOX;
471 dot->m_flag &= ~MPRESERVE;
472 }
473 return(0);
474}
2470b1d8
KS
475
476/*
477 * List the folders the user currently has.
478 */
479folders()
480{
2470b1d8
KS
481 char dirname[BUFSIZ], cmd[BUFSIZ];
482 int pid, s, e;
483
a5bfa0a3
KS
484 if (getfold(dirname) < 0) {
485 printf("No value set for \"folder\"\n");
2470b1d8
KS
486 return(-1);
487 }
2470b1d8
KS
488 switch ((pid = fork())) {
489 case 0:
64df7743 490 sigchild();
a5bfa0a3 491 execlp("ls", "ls", dirname, 0);
80187484 492 _exit(1);
2470b1d8
KS
493
494 case -1:
495 perror("fork");
496 return(-1);
497
498 default:
499 while ((e = wait(&s)) != -1 && e != pid)
500 ;
501 }
502 return(0);
503}