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