1 /*-
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 04/20/95";
10 #endif /* not lint */
11
12 #include "rcv.h"
13 #include "extern.h"
14
15 /*
16 * Mail -- a mail program
17 *
18 * User commands.
19 */
20
21 /*
22 * Print the current active headings.
23 * Don't change dot if invoker didn't give an argument.
24 */
25
26 static int screen;
27
28 int
headers(msgvec)29 headers(msgvec)
30 int *msgvec;
31 {
32 register int n, mesg, flag;
33 register struct message *mp;
34 int size;
35
36 size = screensize();
37 n = msgvec[0];
38 if (n != 0)
39 screen = (n-1)/size;
40 if (screen < 0)
41 screen = 0;
42 mp = &message[screen * size];
43 if (mp >= &message[msgCount])
44 mp = &message[msgCount - size];
45 if (mp < &message[0])
46 mp = &message[0];
47 flag = 0;
48 mesg = mp - &message[0];
49 if (dot != &message[n-1])
50 dot = mp;
51 for (; mp < &message[msgCount]; mp++) {
52 mesg++;
53 if (mp->m_flag & MDELETED)
54 continue;
55 if (flag++ >= size)
56 break;
57 printhead(mesg);
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 */
69 int
scroll(arg)70 scroll(arg)
71 char arg[];
72 {
73 register int s, size;
74 int cur[1];
75
76 cur[0] = 0;
77 size = screensize();
78 s = screen;
79 switch (*arg) {
80 case 0:
81 case '+':
82 s++;
83 if (s * size > msgCount) {
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
105 /*
106 * Compute screen size.
107 */
108 int
screensize()109 screensize()
110 {
111 int s;
112 char *cp;
113
114 if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0)
115 return s;
116 return screenheight - 4;
117 }
118
119 /*
120 * Print out the headlines for each message
121 * in the passed message list.
122 */
123 int
from(msgvec)124 from(msgvec)
125 int *msgvec;
126 {
127 register int *ip;
128
129 for (ip = msgvec; *ip != NULL; ip++)
130 printhead(*ip);
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 */
140 void
printhead(mesg)141 printhead(mesg)
142 int mesg;
143 {
144 struct message *mp;
145 char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
146 char pbuf[BUFSIZ];
147 struct headline hl;
148 int subjlen;
149 char *name;
150
151 mp = &message[mesg-1];
152 (void) readline(setinput(mp), headline, LINESIZE);
153 if ((subjline = hfield("subject", mp)) == NOSTR)
154 subjline = hfield("subj", mp);
155 /*
156 * Bletch!
157 */
158 curind = dot == mp ? '>' : ' ';
159 dispc = ' ';
160 if (mp->m_flag & MSAVED)
161 dispc = '*';
162 if (mp->m_flag & MPRESERVE)
163 dispc = 'P';
164 if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
165 dispc = 'N';
166 if ((mp->m_flag & (MREAD|MNEW)) == 0)
167 dispc = 'U';
168 if (mp->m_flag & MBOX)
169 dispc = 'M';
170 parse(headline, &hl, pbuf);
171 sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size);
172 subjlen = screenwidth - 50 - strlen(wcount);
173 name = value("show-rcpt") != NOSTR ?
174 skin(hfield("to", mp)) : nameof(mp, 0);
175 if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */
176 printf("%c%c%3d %-20.20s %16.16s %s\n",
177 curind, dispc, mesg, name, hl.l_date, wcount);
178 else
179 printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n",
180 curind, dispc, mesg, name, hl.l_date, wcount,
181 subjlen, subjline);
182 }
183
184 /*
185 * Print out the value of dot.
186 */
187 int
pdot()188 pdot()
189 {
190 printf("%d\n", dot - &message[0] + 1);
191 return(0);
192 }
193
194 /*
195 * Print out all the possible commands.
196 */
197 int
pcmdlist()198 pcmdlist()
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
219 /*
220 * Paginate messages, honor ignored fields.
221 */
222 int
more(msgvec)223 more(msgvec)
224 int *msgvec;
225 {
226 return (type1(msgvec, 1, 1));
227 }
228
229 /*
230 * Paginate messages, even printing ignored fields.
231 */
232 int
More(msgvec)233 More(msgvec)
234 int *msgvec;
235 {
236
237 return (type1(msgvec, 0, 1));
238 }
239
240 /*
241 * Type out messages, honor ignored fields.
242 */
243 int
type(msgvec)244 type(msgvec)
245 int *msgvec;
246 {
247
248 return(type1(msgvec, 1, 0));
249 }
250
251 /*
252 * Type out messages, even printing ignored fields.
253 */
254 int
Type(msgvec)255 Type(msgvec)
256 int *msgvec;
257 {
258
259 return(type1(msgvec, 0, 0));
260 }
261
262 /*
263 * Type out the messages requested.
264 */
265 jmp_buf pipestop;
266 int
type1(msgvec,doign,page)267 type1(msgvec, doign, page)
268 int *msgvec;
269 int doign, page;
270 {
271 register *ip;
272 register struct message *mp;
273 register char *cp;
274 int nlines;
275 FILE *obuf;
276
277 obuf = stdout;
278 if (setjmp(pipestop))
279 goto close_pipe;
280 if (value("interactive") != NOSTR &&
281 (page || (cp = value("crt")) != NOSTR)) {
282 nlines = 0;
283 if (!page) {
284 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
285 nlines += message[*ip - 1].m_lines;
286 }
287 if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
288 cp = value("PAGER");
289 if (cp == NULL || *cp == '\0')
290 cp = _PATH_MORE;
291 obuf = Popen(cp, "w");
292 if (obuf == NULL) {
293 perror(cp);
294 obuf = stdout;
295 } else
296 signal(SIGPIPE, brokpipe);
297 }
298 }
299 for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
300 mp = &message[*ip - 1];
301 touch(mp);
302 dot = mp;
303 if (value("quiet") == NOSTR)
304 fprintf(obuf, "Message %d:\n", *ip);
305 (void) send(mp, obuf, doign ? ignore : 0, NOSTR);
306 }
307 close_pipe:
308 if (obuf != stdout) {
309 /*
310 * Ignore SIGPIPE so it can't cause a duplicate close.
311 */
312 signal(SIGPIPE, SIG_IGN);
313 Pclose(obuf);
314 signal(SIGPIPE, SIG_DFL);
315 }
316 return(0);
317 }
318
319 /*
320 * Respond to a broken pipe signal --
321 * probably caused by quitting more.
322 */
323 void
brokpipe(signo)324 brokpipe(signo)
325 int signo;
326 {
327 longjmp(pipestop, 1);
328 }
329
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 */
335 int
top(msgvec)336 top(msgvec)
337 int *msgvec;
338 {
339 register int *ip;
340 register struct message *mp;
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++) {
354 mp = &message[*ip - 1];
355 touch(mp);
356 dot = mp;
357 if (value("quiet") == NOSTR)
358 printf("Message %d:\n", *ip);
359 ibuf = setinput(mp);
360 c = mp->m_lines;
361 if (!lineb)
362 printf("\n");
363 for (lines = 0; lines < c && lines <= topl; lines++) {
364 if (readline(ibuf, linebuf, LINESIZE) < 0)
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 */
377 int
stouch(msgvec)378 stouch(msgvec)
379 int msgvec[];
380 {
381 register int *ip;
382
383 for (ip = msgvec; *ip != 0; ip++) {
384 dot = &message[*ip-1];
385 dot->m_flag |= MTOUCH;
386 dot->m_flag &= ~MPRESERVE;
387 }
388 return(0);
389 }
390
391 /*
392 * Make sure all passed messages get mboxed.
393 */
394 int
mboxit(msgvec)395 mboxit(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 }
407
408 /*
409 * List the folders the user currently has.
410 */
411 int
folders()412 folders()
413 {
414 char dirname[BUFSIZ];
415 char *cmd;
416
417 if (getfold(dirname) < 0) {
418 printf("No value set for \"folder\"\n");
419 return 1;
420 }
421 if ((cmd = value("LISTER")) == NOSTR)
422 cmd = "ls";
423 (void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR);
424 return 0;
425 }
426
427 /*
428 * Update the mail file with any new messages that have
429 * come in since we started reading mail.
430 */
inc()431 inc()
432 {
433 int nmsg, mdot;
434
435 nmsg = incfile();
436
437 if (nmsg == 0) {
438 printf("No new mail.\n");
439 } else if (nmsg > 0) {
440 mdot = newfileinfo(msgCount - nmsg);
441 dot = &message[mdot - 1];
442 } else {
443 printf("\"inc\" command failed...\n");
444 }
445
446 return 0;
447 }
448