cmd1.c revision 1.7 1 /* $NetBSD: cmd1.c,v 1.7 1997/05/13 06:15:53 mikel Exp $ */
2
3 /*-
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95";
39 #else
40 static char rcsid[] = "$NetBSD: cmd1.c,v 1.7 1997/05/13 06:15:53 mikel Exp $";
41 #endif
42 #endif /* not lint */
43
44 #include "rcv.h"
45 #include "extern.h"
46
47 /*
48 * Mail -- a mail program
49 *
50 * User commands.
51 */
52
53 /*
54 * Print the current active headings.
55 * Don't change dot if invoker didn't give an argument.
56 */
57
58 static int screen;
59
60 int
61 headers(v)
62 void *v;
63 {
64 int *msgvec = v;
65 register int n, mesg, flag;
66 register struct message *mp;
67 int size;
68
69 size = screensize();
70 n = msgvec[0];
71 if (n != 0)
72 screen = (n-1)/size;
73 if (screen < 0)
74 screen = 0;
75 mp = &message[screen * size];
76 if (mp >= &message[msgCount])
77 mp = &message[msgCount - size];
78 if (mp < &message[0])
79 mp = &message[0];
80 flag = 0;
81 mesg = mp - &message[0];
82 if (dot != &message[n-1])
83 dot = mp;
84 for (; mp < &message[msgCount]; mp++) {
85 mesg++;
86 if (mp->m_flag & MDELETED)
87 continue;
88 if (flag++ >= size)
89 break;
90 printhead(mesg);
91 }
92 if (flag == 0) {
93 printf("No more mail.\n");
94 return(1);
95 }
96 return(0);
97 }
98
99 /*
100 * Scroll to the next/previous screen
101 */
102 int
103 scroll(v)
104 void *v;
105 {
106 char *arg = v;
107 register int s, size;
108 int cur[1];
109
110 cur[0] = 0;
111 size = screensize();
112 s = screen;
113 switch (*arg) {
114 case 0:
115 case '+':
116 s++;
117 if (s * size > msgCount) {
118 printf("On last screenful of messages\n");
119 return(0);
120 }
121 screen = s;
122 break;
123
124 case '-':
125 if (--s < 0) {
126 printf("On first screenful of messages\n");
127 return(0);
128 }
129 screen = s;
130 break;
131
132 default:
133 printf("Unrecognized scrolling command \"%s\"\n", arg);
134 return(1);
135 }
136 return(headers(cur));
137 }
138
139 /*
140 * Compute screen size.
141 */
142 int
143 screensize()
144 {
145 int s;
146 char *cp;
147
148 if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0)
149 return s;
150 return screenheight - 4;
151 }
152
153 /*
154 * Print out the headlines for each message
155 * in the passed message list.
156 */
157 int
158 from(v)
159 void *v;
160 {
161 int *msgvec = v;
162 register int *ip;
163
164 for (ip = msgvec; *ip != NULL; ip++)
165 printhead(*ip);
166 if (--ip >= msgvec)
167 dot = &message[*ip - 1];
168 return(0);
169 }
170
171 /*
172 * Print out the header of a specific message.
173 * This is a slight improvement to the standard one.
174 */
175 void
176 printhead(mesg)
177 int mesg;
178 {
179 struct message *mp;
180 char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
181 char pbuf[BUFSIZ];
182 struct headline hl;
183 int subjlen;
184 char *name;
185
186 mp = &message[mesg-1];
187 (void) readline(setinput(mp), headline, LINESIZE);
188 if ((subjline = hfield("subject", mp)) == NOSTR)
189 subjline = hfield("subj", mp);
190 /*
191 * Bletch!
192 */
193 curind = dot == mp ? '>' : ' ';
194 dispc = ' ';
195 if (mp->m_flag & MSAVED)
196 dispc = '*';
197 if (mp->m_flag & MPRESERVE)
198 dispc = 'P';
199 if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
200 dispc = 'N';
201 if ((mp->m_flag & (MREAD|MNEW)) == 0)
202 dispc = 'U';
203 if (mp->m_flag & MBOX)
204 dispc = 'M';
205 parse(headline, &hl, pbuf);
206 snprintf(wcount, LINESIZE, "%3d/%-5ld", mp->m_lines, mp->m_size);
207 subjlen = screenwidth - 50 - strlen(wcount);
208 name = value("show-rcpt") != NOSTR ?
209 skin(hfield("to", mp)) : nameof(mp, 0);
210 if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */
211 printf("%c%c%3d %-20.20s %16.16s %s\n",
212 curind, dispc, mesg, name, hl.l_date, wcount);
213 else
214 printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n",
215 curind, dispc, mesg, name, hl.l_date, wcount,
216 subjlen, subjline);
217 }
218
219 /*
220 * Print out the value of dot.
221 */
222 int
223 pdot(v)
224 void *v;
225 {
226 printf("%d\n", dot - &message[0] + 1);
227 return(0);
228 }
229
230 /*
231 * Print out all the possible commands.
232 */
233 int
234 pcmdlist(v)
235 void *v;
236 {
237 extern const struct cmd cmdtab[];
238 register const struct cmd *cp;
239 register int cc;
240
241 printf("Commands are:\n");
242 for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
243 cc += strlen(cp->c_name) + 2;
244 if (cc > 72) {
245 printf("\n");
246 cc = strlen(cp->c_name) + 2;
247 }
248 if ((cp+1)->c_name != NOSTR)
249 printf("%s, ", cp->c_name);
250 else
251 printf("%s\n", cp->c_name);
252 }
253 return(0);
254 }
255
256 /*
257 * Paginate messages, honor ignored fields.
258 */
259 int
260 more(v)
261 void *v;
262 {
263 int *msgvec = v;
264 return (type1(msgvec, 1, 1));
265 }
266
267 /*
268 * Paginate messages, even printing ignored fields.
269 */
270 int
271 More(v)
272 void *v;
273 {
274 int *msgvec = v;
275
276 return (type1(msgvec, 0, 1));
277 }
278
279 /*
280 * Type out messages, honor ignored fields.
281 */
282 int
283 type(v)
284 void *v;
285 {
286 int *msgvec = v;
287
288 return(type1(msgvec, 1, 0));
289 }
290
291 /*
292 * Type out messages, even printing ignored fields.
293 */
294 int
295 Type(v)
296 void *v;
297 {
298 int *msgvec = v;
299
300 return(type1(msgvec, 0, 0));
301 }
302
303 /*
304 * Type out the messages requested.
305 */
306 jmp_buf pipestop;
307 int
308 type1(msgvec, doign, page)
309 int *msgvec;
310 int doign, page;
311 {
312 register *ip;
313 struct message *mp;
314 char *cp;
315 int nlines;
316 FILE *obuf;
317 #if __GNUC__
318 /* Avoid longjmp clobbering */
319 (void) &cp;
320 (void) &obuf;
321 #endif
322
323 obuf = stdout;
324 if (setjmp(pipestop))
325 goto close_pipe;
326 if (value("interactive") != NOSTR &&
327 (page || (cp = value("crt")) != NOSTR)) {
328 nlines = 0;
329 if (!page) {
330 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
331 nlines += message[*ip - 1].m_lines;
332 }
333 if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
334 cp = value("PAGER");
335 if (cp == NULL || *cp == '\0')
336 cp = _PATH_MORE;
337 obuf = Popen(cp, "w");
338 if (obuf == NULL) {
339 perror(cp);
340 obuf = stdout;
341 } else
342 signal(SIGPIPE, brokpipe);
343 }
344 }
345 for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
346 mp = &message[*ip - 1];
347 touch(mp);
348 dot = mp;
349 if (value("quiet") == NOSTR)
350 fprintf(obuf, "Message %d:\n", *ip);
351 (void) send(mp, obuf, doign ? ignore : 0, NOSTR);
352 }
353 close_pipe:
354 if (obuf != stdout) {
355 /*
356 * Ignore SIGPIPE so it can't cause a duplicate close.
357 */
358 signal(SIGPIPE, SIG_IGN);
359 Pclose(obuf);
360 signal(SIGPIPE, SIG_DFL);
361 }
362 return(0);
363 }
364
365 /*
366 * Respond to a broken pipe signal --
367 * probably caused by quitting more.
368 */
369 void
370 brokpipe(signo)
371 int signo;
372 {
373 longjmp(pipestop, 1);
374 }
375
376 /*
377 * Print the top so many lines of each desired message.
378 * The number of lines is taken from the variable "toplines"
379 * and defaults to 5.
380 */
381 int
382 top(v)
383 void *v;
384 {
385 int *msgvec = v;
386 register int *ip;
387 register struct message *mp;
388 int c, topl, lines, lineb;
389 char *valtop, linebuf[LINESIZE];
390 FILE *ibuf;
391
392 topl = 5;
393 valtop = value("toplines");
394 if (valtop != NOSTR) {
395 topl = atoi(valtop);
396 if (topl < 0 || topl > 10000)
397 topl = 5;
398 }
399 lineb = 1;
400 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
401 mp = &message[*ip - 1];
402 touch(mp);
403 dot = mp;
404 if (value("quiet") == NOSTR)
405 printf("Message %d:\n", *ip);
406 ibuf = setinput(mp);
407 c = mp->m_lines;
408 if (!lineb)
409 printf("\n");
410 for (lines = 0; lines < c && lines <= topl; lines++) {
411 if (readline(ibuf, linebuf, LINESIZE) < 0)
412 break;
413 puts(linebuf);
414 lineb = blankline(linebuf);
415 }
416 }
417 return(0);
418 }
419
420 /*
421 * Touch all the given messages so that they will
422 * get mboxed.
423 */
424 int
425 stouch(v)
426 void *v;
427 {
428 int *msgvec = v;
429 register int *ip;
430
431 for (ip = msgvec; *ip != 0; ip++) {
432 dot = &message[*ip-1];
433 dot->m_flag |= MTOUCH;
434 dot->m_flag &= ~MPRESERVE;
435 }
436 return(0);
437 }
438
439 /*
440 * Make sure all passed messages get mboxed.
441 */
442 int
443 mboxit(v)
444 void *v;
445 {
446 int *msgvec = v;
447 register int *ip;
448
449 for (ip = msgvec; *ip != 0; ip++) {
450 dot = &message[*ip-1];
451 dot->m_flag |= MTOUCH|MBOX;
452 dot->m_flag &= ~MPRESERVE;
453 }
454 return(0);
455 }
456
457 /*
458 * List the folders the user currently has.
459 */
460 int
461 folders(v)
462 void *v;
463 {
464 char dirname[PATHSIZE];
465 char *cmd;
466
467 if (getfold(dirname) < 0) {
468 printf("No value set for \"folder\"\n");
469 return 1;
470 }
471 if ((cmd = value("LISTER")) == NOSTR)
472 cmd = "ls";
473 (void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR);
474 return 0;
475 }
476
477 /*
478 * Update the mail file with any new messages that have
479 * come in since we started reading mail.
480 */
481 int
482 inc(v)
483 void *v;
484 {
485 int nmsg, mdot;
486
487 nmsg = incfile();
488
489 if (nmsg == 0) {
490 printf("No new mail.\n");
491 } else if (nmsg > 0) {
492 mdot = newfileinfo(msgCount - nmsg);
493 dot = &message[mdot - 1];
494 } else {
495 printf("\"inc\" command failed...\n");
496 }
497
498 return 0;
499 }
500