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