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