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