4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / usr.bin / mail / cmd1.c
CommitLineData
d3dde041 1/*-
a12ff486
KB
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
0c5f72fb 4 *
d3dde041 5 * %sccs.include.redist.c%
b059c7be
DF
6 */
7
acfc7e9b 8#ifndef lint
a12ff486 9static char sccsid[] = "@(#)cmd1.c 8.1 (Berkeley) %G%";
acfc7e9b 10#endif /* not lint */
2ae9f53f 11
d702437a 12#include "rcv.h"
a0d23834 13#include "extern.h"
d702437a
KS
14
15/*
16 * Mail -- a mail program
17 *
18 * User commands.
19 */
20
d702437a
KS
21/*
22 * Print the current active headings.
f75dd1e5 23 * Don't change dot if invoker didn't give an argument.
d702437a
KS
24 */
25
26static int screen;
27
a0d23834 28int
d702437a
KS
29headers(msgvec)
30 int *msgvec;
31{
32 register int n, mesg, flag;
33 register struct message *mp;
1491ef97 34 int size;
d702437a 35
1491ef97 36 size = screensize();
d702437a
KS
37 n = msgvec[0];
38 if (n != 0)
1491ef97 39 screen = (n-1)/size;
d702437a
KS
40 if (screen < 0)
41 screen = 0;
1491ef97 42 mp = &message[screen * size];
d702437a 43 if (mp >= &message[msgCount])
1491ef97 44 mp = &message[msgCount - size];
d702437a
KS
45 if (mp < &message[0])
46 mp = &message[0];
47 flag = 0;
48 mesg = mp - &message[0];
f75dd1e5
KS
49 if (dot != &message[n-1])
50 dot = mp;
d702437a
KS
51 for (; mp < &message[msgCount]; mp++) {
52 mesg++;
53 if (mp->m_flag & MDELETED)
54 continue;
1491ef97 55 if (flag++ >= size)
d702437a
KS
56 break;
57 printhead(mesg);
d702437a
KS
58 }
59 if (flag == 0) {
60 printf("No more mail.\n");
61 return(1);
62 }
63 return(0);
64}
65
66/*
67 * Scroll to the next/previous screen
68 */
a0d23834 69int
d702437a
KS
70scroll(arg)
71 char arg[];
72{
1491ef97 73 register int s, size;
d702437a
KS
74 int cur[1];
75
76 cur[0] = 0;
1491ef97 77 size = screensize();
d702437a
KS
78 s = screen;
79 switch (*arg) {
80 case 0:
81 case '+':
82 s++;
1491ef97 83 if (s * size > msgCount) {
d702437a
KS
84 printf("On last screenful of messages\n");
85 return(0);
86 }
87 screen = s;
88 break;
89
90 case '-':
91 if (--s < 0) {
92 printf("On first screenful of messages\n");
93 return(0);
94 }
95 screen = s;
96 break;
97
98 default:
99 printf("Unrecognized scrolling command \"%s\"\n", arg);
100 return(1);
101 }
102 return(headers(cur));
103}
104
1491ef97 105/*
828615a1 106 * Compute screen size.
1491ef97 107 */
a0d23834 108int
1491ef97
KS
109screensize()
110{
828615a1
EW
111 int s;
112 char *cp;
113
114 if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0)
115 return s;
116 return screenheight - 4;
1491ef97 117}
d702437a
KS
118
119/*
120 * Print out the headlines for each message
121 * in the passed message list.
122 */
a0d23834 123int
d702437a
KS
124from(msgvec)
125 int *msgvec;
126{
127 register int *ip;
128
f674e088 129 for (ip = msgvec; *ip != NULL; ip++)
d702437a 130 printhead(*ip);
d702437a
KS
131 if (--ip >= msgvec)
132 dot = &message[*ip - 1];
133 return(0);
134}
135
136/*
137 * Print out the header of a specific message.
138 * This is a slight improvement to the standard one.
139 */
a0d23834 140void
d702437a 141printhead(mesg)
a0d23834 142 int mesg;
d702437a
KS
143{
144 struct message *mp;
2d7425cf 145 char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
d702437a 146 char pbuf[BUFSIZ];
d702437a 147 struct headline hl;
828615a1 148 int subjlen;
d3dde041 149 char *name;
d702437a
KS
150
151 mp = &message[mesg-1];
38ed7007 152 (void) readline(setinput(mp), headline, LINESIZE);
828615a1 153 if ((subjline = hfield("subject", mp)) == NOSTR)
d702437a 154 subjline = hfield("subj", mp);
d702437a
KS
155 /*
156 * Bletch!
157 */
f75dd1e5 158 curind = dot == mp ? '>' : ' ';
d702437a
KS
159 dispc = ' ';
160 if (mp->m_flag & MSAVED)
161 dispc = '*';
162 if (mp->m_flag & MPRESERVE)
163 dispc = 'P';
5bfbbe88 164 if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
f4d36a07 165 dispc = 'N';
5bfbbe88
KS
166 if ((mp->m_flag & (MREAD|MNEW)) == 0)
167 dispc = 'U';
f2230dfd
KS
168 if (mp->m_flag & MBOX)
169 dispc = 'M';
d702437a 170 parse(headline, &hl, pbuf);
d3dde041 171 sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size);
828615a1 172 subjlen = screenwidth - 50 - strlen(wcount);
d3dde041
EW
173 name = value("show-rcpt") != NOSTR ?
174 skin(hfield("to", mp)) : nameof(mp, 0);
828615a1
EW
175 if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */
176 printf("%c%c%3d %-20.20s %16.16s %s\n",
d3dde041 177 curind, dispc, mesg, name, hl.l_date, wcount);
d702437a 178 else
828615a1 179 printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n",
d3dde041 180 curind, dispc, mesg, name, hl.l_date, wcount,
828615a1 181 subjlen, subjline);
d702437a
KS
182}
183
184/*
185 * Print out the value of dot.
186 */
a0d23834 187int
d702437a
KS
188pdot()
189{
190 printf("%d\n", dot - &message[0] + 1);
191 return(0);
192}
193
194/*
195 * Print out all the possible commands.
196 */
a0d23834 197int
d702437a
KS
198pcmdlist()
199{
200 register struct cmd *cp;
201 register int cc;
202 extern struct cmd cmdtab[];
203
204 printf("Commands are:\n");
205 for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
206 cc += strlen(cp->c_name) + 2;
207 if (cc > 72) {
208 printf("\n");
209 cc = strlen(cp->c_name) + 2;
210 }
211 if ((cp+1)->c_name != NOSTR)
212 printf("%s, ", cp->c_name);
213 else
214 printf("%s\n", cp->c_name);
215 }
216 return(0);
217}
218
b041ccec
S
219/*
220 * Paginate messages, honor ignored fields.
221 */
a0d23834 222int
b041ccec
S
223more(msgvec)
224 int *msgvec;
225{
226 return (type1(msgvec, 1, 1));
227}
228
229/*
230 * Paginate messages, even printing ignored fields.
231 */
a0d23834 232int
b041ccec
S
233More(msgvec)
234 int *msgvec;
235{
236
237 return (type1(msgvec, 0, 1));
238}
239
d702437a 240/*
15bff4bb 241 * Type out messages, honor ignored fields.
d702437a 242 */
a0d23834 243int
15bff4bb
KS
244type(msgvec)
245 int *msgvec;
246{
d702437a 247
b041ccec 248 return(type1(msgvec, 1, 0));
15bff4bb
KS
249}
250
251/*
252 * Type out messages, even printing ignored fields.
253 */
a0d23834 254int
15bff4bb
KS
255Type(msgvec)
256 int *msgvec;
257{
258
b041ccec 259 return(type1(msgvec, 0, 0));
15bff4bb
KS
260}
261
262/*
263 * Type out the messages requested.
264 */
740867ff 265jmp_buf pipestop;
a0d23834 266int
b041ccec 267type1(msgvec, doign, page)
d702437a 268 int *msgvec;
a0d23834 269 int doign, page;
d702437a
KS
270{
271 register *ip;
272 register struct message *mp;
740867ff 273 register char *cp;
828615a1 274 int nlines;
828615a1 275 FILE *obuf;
740867ff
KS
276
277 obuf = stdout;
07b0d286
EW
278 if (setjmp(pipestop))
279 goto close_pipe;
686f6134
EW
280 if (value("interactive") != NOSTR &&
281 (page || (cp = value("crt")) != NOSTR)) {
2d7425cf 282 nlines = 0;
b041ccec 283 if (!page) {
b041ccec
S
284 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
285 nlines += message[*ip - 1].m_lines;
286 }
d56fd190 287 if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
2d7425cf
S
288 cp = value("PAGER");
289 if (cp == NULL || *cp == '\0')
435e8dff 290 cp = _PATH_MORE;
d96977db 291 obuf = Popen(cp, "w");
740867ff 292 if (obuf == NULL) {
2d7425cf 293 perror(cp);
740867ff 294 obuf = stdout;
07b0d286 295 } else
828615a1 296 signal(SIGPIPE, brokpipe);
740867ff
KS
297 }
298 }
828615a1 299 for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
470c33f3
EW
300 mp = &message[*ip - 1];
301 touch(mp);
d702437a 302 dot = mp;
828615a1 303 if (value("quiet") == NOSTR)
470c33f3 304 fprintf(obuf, "Message %d:\n", *ip);
2de8fc95 305 (void) send(mp, obuf, doign ? ignore : 0, NOSTR);
740867ff 306 }
07b0d286 307close_pipe:
740867ff 308 if (obuf != stdout) {
07b0d286
EW
309 /*
310 * Ignore SIGPIPE so it can't cause a duplicate close.
311 */
312 signal(SIGPIPE, SIG_IGN);
d96977db 313 Pclose(obuf);
07b0d286 314 signal(SIGPIPE, SIG_DFL);
d702437a
KS
315 }
316 return(0);
317}
318
740867ff
KS
319/*
320 * Respond to a broken pipe signal --
07b0d286 321 * probably caused by quitting more.
740867ff 322 */
a6714963 323void
a0d23834
KB
324brokpipe(signo)
325 int signo;
740867ff 326{
fc3f7633 327 longjmp(pipestop, 1);
740867ff
KS
328}
329
d702437a
KS
330/*
331 * Print the top so many lines of each desired message.
332 * The number of lines is taken from the variable "toplines"
333 * and defaults to 5.
334 */
a0d23834 335int
d702437a
KS
336top(msgvec)
337 int *msgvec;
338{
339 register int *ip;
340 register struct message *mp;
d702437a
KS
341 int c, topl, lines, lineb;
342 char *valtop, linebuf[LINESIZE];
343 FILE *ibuf;
344
345 topl = 5;
346 valtop = value("toplines");
347 if (valtop != NOSTR) {
348 topl = atoi(valtop);
349 if (topl < 0 || topl > 10000)
350 topl = 5;
351 }
352 lineb = 1;
353 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
470c33f3
EW
354 mp = &message[*ip - 1];
355 touch(mp);
d702437a
KS
356 dot = mp;
357 if (value("quiet") == NOSTR)
470c33f3 358 printf("Message %d:\n", *ip);
d702437a
KS
359 ibuf = setinput(mp);
360 c = mp->m_lines;
361 if (!lineb)
362 printf("\n");
363 for (lines = 0; lines < c && lines <= topl; lines++) {
38ed7007 364 if (readline(ibuf, linebuf, LINESIZE) < 0)
d702437a
KS
365 break;
366 puts(linebuf);
367 lineb = blankline(linebuf);
368 }
369 }
370 return(0);
371}
372
373/*
374 * Touch all the given messages so that they will
375 * get mboxed.
376 */
a0d23834 377int
d702437a
KS
378stouch(msgvec)
379 int msgvec[];
380{
381 register int *ip;
382
383 for (ip = msgvec; *ip != 0; ip++) {
d702437a 384 dot = &message[*ip-1];
5bfbbe88 385 dot->m_flag |= MTOUCH;
d702437a
KS
386 dot->m_flag &= ~MPRESERVE;
387 }
388 return(0);
389}
f2230dfd
KS
390
391/*
392 * Make sure all passed messages get mboxed.
393 */
a0d23834 394int
f2230dfd
KS
395mboxit(msgvec)
396 int msgvec[];
397{
398 register int *ip;
399
400 for (ip = msgvec; *ip != 0; ip++) {
401 dot = &message[*ip-1];
402 dot->m_flag |= MTOUCH|MBOX;
403 dot->m_flag &= ~MPRESERVE;
404 }
405 return(0);
406}
2470b1d8
KS
407
408/*
409 * List the folders the user currently has.
410 */
a0d23834 411int
2470b1d8
KS
412folders()
413{
828615a1 414 char dirname[BUFSIZ];
d33aa50d 415 char *cmd;
2470b1d8 416
a5bfa0a3
KS
417 if (getfold(dirname) < 0) {
418 printf("No value set for \"folder\"\n");
2ee3bce2 419 return 1;
2470b1d8 420 }
d33aa50d
EW
421 if ((cmd = value("LISTER")) == NOSTR)
422 cmd = "ls";
a0d23834 423 (void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR);
d33aa50d 424 return 0;
2470b1d8 425}