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