Annotation of src/usr.bin/mail/cmd1.c, Revision 1.24
1.24 ! millert 1: /* $OpenBSD: cmd1.c,v 1.23 2003/05/15 02:47:47 pjanzen 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.24 ! millert 37: static const char rcsid[] = "$OpenBSD: cmd1.c,v 1.23 2003/05/15 02:47:47 pjanzen 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];
69: if (n != 0)
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.13 millert 125: maxscreen = (msgCount - 1) / size;
1.1 deraadt 126: switch (*arg) {
127: case 0:
128: case '+':
1.13 millert 129: if (screen >= maxscreen) {
1.6 millert 130: puts("On last screenful of messages");
1.1 deraadt 131: return(0);
132: }
1.13 millert 133: screen++;
1.1 deraadt 134: break;
135:
136: case '-':
1.13 millert 137: if (screen <= 0) {
1.6 millert 138: puts("On first screenful of messages");
1.1 deraadt 139: return(0);
140: }
1.13 millert 141: screen--;
1.1 deraadt 142: break;
143:
144: default:
145: printf("Unrecognized scrolling command \"%s\"\n", arg);
146: return(1);
147: }
148: return(headers(cur));
149: }
150:
151: /*
152: * Compute screen size.
153: */
154: int
1.21 millert 155: screensize(void)
1.1 deraadt 156: {
157: int s;
158: char *cp;
159:
1.8 millert 160: if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0)
1.6 millert 161: return(s);
162: return(screenheight - 4);
1.1 deraadt 163: }
164:
165: /*
166: * Print out the headlines for each message
167: * in the passed message list.
168: */
169: int
1.21 millert 170: from(void *v)
1.1 deraadt 171: {
1.3 deraadt 172: int *msgvec = v;
1.12 millert 173: int *ip;
1.1 deraadt 174:
175: for (ip = msgvec; *ip != NULL; ip++)
176: printhead(*ip);
177: if (--ip >= msgvec)
178: dot = &message[*ip - 1];
179: return(0);
180: }
181:
182: /*
183: * Print out the header of a specific message.
184: * This is a slight improvement to the standard one.
185: */
186: void
1.21 millert 187: printhead(int mesg)
1.1 deraadt 188: {
189: struct message *mp;
190: char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
1.23 pjanzen 191: char visline[LINESIZE];
1.1 deraadt 192: char pbuf[BUFSIZ];
193: struct headline hl;
194: int subjlen;
195: char *name;
1.17 millert 196: char *to, *from;
197: struct name *np;
198: char **ap;
1.1 deraadt 199:
200: mp = &message[mesg-1];
1.20 millert 201: (void)readline(setinput(mp), headline, LINESIZE, NULL);
1.8 millert 202: if ((subjline = hfield("subject", mp)) == NULL)
1.1 deraadt 203: subjline = hfield("subj", mp);
204: /*
205: * Bletch!
206: */
207: curind = dot == mp ? '>' : ' ';
208: dispc = ' ';
209: if (mp->m_flag & MSAVED)
210: dispc = '*';
211: if (mp->m_flag & MPRESERVE)
212: dispc = 'P';
213: if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
214: dispc = 'N';
215: if ((mp->m_flag & (MREAD|MNEW)) == 0)
216: dispc = 'U';
217: if (mp->m_flag & MBOX)
218: dispc = 'M';
219: parse(headline, &hl, pbuf);
1.17 millert 220: (void)snprintf(wcount, sizeof(wcount), "%4d/%-5d", mp->m_lines,
1.10 millert 221: mp->m_size);
1.17 millert 222: subjlen = screenwidth - 44 - strlen(wcount);
223: from = nameof(mp, 0);
224: to = skin(hfield("to", mp));
225: np = extract(from, GTO);
226: np = delname(np, myname);
227: if (altnames)
228: for (ap = altnames; *ap; ap++)
229: np = delname(np, *ap);
230: if (np)
231: /* not from me */
232: name = value("show-rcpt") != NULL && to ? to : from;
1.1 deraadt 233: else
1.17 millert 234: /* from me - show TO */
235: name = value("showto") != NULL && to ? to : from;
236: if (subjline == NULL || subjlen < 0) { /* pretty pathetic */
237: subjline="";
238: subjlen=0;
239: }
1.23 pjanzen 240: printf("%c%c%3d ", curind, dispc, mesg);
241: strnvis(visline, name, sizeof(visline), VIS_SAFE|VIS_NOSLASH);
1.17 millert 242: if (name == to)
1.23 pjanzen 243: printf("TO %-14.14s", visline);
1.17 millert 244: else
1.23 pjanzen 245: printf("%-17.17s", visline);
246: /* hl.l_date was sanity-checked when read in. wcount we just made. */
247: strnvis(visline, subjline, sizeof(visline), VIS_SAFE|VIS_NOSLASH);
248: printf(" %16.16s %s %.*s\n", hl.l_date, wcount, subjlen, visline);
1.1 deraadt 249: }
250:
251: /*
252: * Print out the value of dot.
253: */
254: int
1.21 millert 255: pdot(void *v)
1.1 deraadt 256: {
1.12 millert 257: printf("%d\n", (int)(dot - &message[0] + 1));
1.1 deraadt 258: return(0);
259: }
260:
261: /*
262: * Print out all the possible commands.
263: */
264: int
1.21 millert 265: pcmdlist(void *v)
1.1 deraadt 266: {
1.2 niklas 267: extern const struct cmd cmdtab[];
1.12 millert 268: const struct cmd *cp;
269: int cc;
1.1 deraadt 270:
1.6 millert 271: puts("Commands are:");
1.1 deraadt 272: for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
273: cc += strlen(cp->c_name) + 2;
274: if (cc > 72) {
1.6 millert 275: putchar('\n');
1.1 deraadt 276: cc = strlen(cp->c_name) + 2;
277: }
1.8 millert 278: if ((cp+1)->c_name != NULL)
1.1 deraadt 279: printf("%s, ", cp->c_name);
280: else
1.6 millert 281: puts(cp->c_name);
1.1 deraadt 282: }
283: return(0);
284: }
285:
286: /*
1.17 millert 287: * Pipe message to command
288: */
289: int
1.21 millert 290: pipeit(void *ml, void *sl)
1.17 millert 291: {
292: int *msgvec = ml;
293: char *cmd = sl;
294:
295: return(type1(msgvec, cmd, 0, 0));
296: }
297:
298: /*
1.1 deraadt 299: * Paginate messages, honor ignored fields.
300: */
301: int
1.21 millert 302: more(void *v)
1.1 deraadt 303: {
1.3 deraadt 304: int *msgvec = v;
1.17 millert 305: return(type1(msgvec, NULL, 1, 1));
1.1 deraadt 306: }
307:
308: /*
309: * Paginate messages, even printing ignored fields.
310: */
311: int
1.21 millert 312: More(void *v)
1.1 deraadt 313: {
1.3 deraadt 314: int *msgvec = v;
1.1 deraadt 315:
1.17 millert 316: return(type1(msgvec, NULL, 0, 1));
1.1 deraadt 317: }
318:
319: /*
320: * Type out messages, honor ignored fields.
321: */
322: int
1.21 millert 323: type(void *v)
1.1 deraadt 324: {
1.3 deraadt 325: int *msgvec = v;
1.1 deraadt 326:
1.17 millert 327: return(type1(msgvec, NULL, 1, 0));
1.1 deraadt 328: }
329:
330: /*
331: * Type out messages, even printing ignored fields.
332: */
333: int
1.21 millert 334: Type(void *v)
1.1 deraadt 335: {
1.3 deraadt 336: int *msgvec = v;
1.1 deraadt 337:
1.17 millert 338: return(type1(msgvec, NULL, 0, 0));
1.1 deraadt 339: }
340:
341: /*
342: * Type out the messages requested.
343: */
344: int
1.21 millert 345: type1(int *msgvec, char *cmd, int doign, int page)
1.1 deraadt 346: {
1.19 millert 347: int nlines, *ip, restoreterm;
1.3 deraadt 348: struct message *mp;
1.19 millert 349: struct termios tbuf;
1.20 millert 350: char *cp;
351: FILE *obuf;
1.1 deraadt 352:
353: obuf = stdout;
1.19 millert 354: restoreterm = 0;
1.17 millert 355:
356: /*
357: * start a pipe if needed.
358: */
359: if (cmd) {
1.19 millert 360: restoreterm = (tcgetattr(fileno(stdin), &tbuf) == 0);
1.17 millert 361: obuf = Popen(cmd, "w");
362: if (obuf == NULL) {
1.20 millert 363: warn("%s", cmd);
1.17 millert 364: obuf = stdout;
365: }
366: } else if (value("interactive") != NULL &&
367: (page || (cp = value("crt")) != NULL)) {
1.1 deraadt 368: nlines = 0;
369: if (!page) {
370: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
371: nlines += message[*ip - 1].m_lines;
372: }
373: if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
1.19 millert 374: restoreterm = (tcgetattr(fileno(stdin), &tbuf) == 0);
1.17 millert 375: obuf = Popen(value("PAGER"), "w");
1.1 deraadt 376: if (obuf == NULL) {
1.16 millert 377: warn("%s", cp);
1.1 deraadt 378: obuf = stdout;
1.20 millert 379: }
1.1 deraadt 380: }
381: }
1.17 millert 382:
383: /*
1.21 millert 384: * Send messages to the output.
1.17 millert 385: */
1.1 deraadt 386: for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
387: mp = &message[*ip - 1];
388: touch(mp);
389: dot = mp;
1.17 millert 390: if (cmd == NULL && value("quiet") == NULL)
1.1 deraadt 391: fprintf(obuf, "Message %d:\n", *ip);
1.19 millert 392: if (sendmessage(mp, obuf, doign ? ignore : 0, NULL) == -1)
393: break;
1.1 deraadt 394: }
1.17 millert 395:
1.1 deraadt 396: if (obuf != stdout) {
1.6 millert 397: (void)Pclose(obuf);
1.19 millert 398: if (restoreterm)
399: (void)tcsetattr(fileno(stdin), TCSADRAIN, &tbuf);
1.1 deraadt 400: }
401: return(0);
402: }
403:
404: /*
405: * Print the top so many lines of each desired message.
406: * The number of lines is taken from the variable "toplines"
407: * and defaults to 5.
408: */
409: int
1.21 millert 410: top(void * v)
1.1 deraadt 411: {
1.3 deraadt 412: int *msgvec = v;
1.12 millert 413: int *ip;
414: struct message *mp;
1.1 deraadt 415: int c, topl, lines, lineb;
416: char *valtop, linebuf[LINESIZE];
417: FILE *ibuf;
418:
419: topl = 5;
420: valtop = value("toplines");
1.8 millert 421: if (valtop != NULL) {
1.1 deraadt 422: topl = atoi(valtop);
423: if (topl < 0 || topl > 10000)
424: topl = 5;
425: }
426: lineb = 1;
427: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
428: mp = &message[*ip - 1];
429: touch(mp);
430: dot = mp;
1.8 millert 431: if (value("quiet") == NULL)
1.1 deraadt 432: printf("Message %d:\n", *ip);
433: ibuf = setinput(mp);
434: c = mp->m_lines;
435: if (!lineb)
1.6 millert 436: putchar('\n');
1.1 deraadt 437: for (lines = 0; lines < c && lines <= topl; lines++) {
1.20 millert 438: if (readline(ibuf, linebuf, sizeof(linebuf), NULL) < 0)
1.1 deraadt 439: break;
440: puts(linebuf);
441: lineb = blankline(linebuf);
442: }
443: }
444: return(0);
445: }
446:
447: /*
448: * Touch all the given messages so that they will
449: * get mboxed.
450: */
451: int
1.21 millert 452: stouch(void *v)
1.1 deraadt 453: {
1.3 deraadt 454: int *msgvec = v;
1.12 millert 455: int *ip;
1.1 deraadt 456:
457: for (ip = msgvec; *ip != 0; ip++) {
458: dot = &message[*ip-1];
459: dot->m_flag |= MTOUCH;
460: dot->m_flag &= ~MPRESERVE;
461: }
462: return(0);
463: }
464:
465: /*
466: * Make sure all passed messages get mboxed.
467: */
468: int
1.21 millert 469: mboxit(void *v)
1.1 deraadt 470: {
1.3 deraadt 471: int *msgvec = v;
1.12 millert 472: int *ip;
1.1 deraadt 473:
474: for (ip = msgvec; *ip != 0; ip++) {
475: dot = &message[*ip-1];
476: dot->m_flag |= MTOUCH|MBOX;
477: dot->m_flag &= ~MPRESERVE;
478: }
479: return(0);
480: }
481:
482: /*
483: * List the folders the user currently has.
484: */
485: int
1.21 millert 486: folders(void *v)
1.1 deraadt 487: {
1.17 millert 488: char *files = (char *)v;
1.5 deraadt 489: char dirname[PATHSIZE];
1.17 millert 490: char cmd[BUFSIZ];
1.1 deraadt 491:
1.22 millert 492: if (getfold(dirname, sizeof(dirname)) < 0)
493: strlcpy(dirname, "$HOME", sizeof(dirname));
1.17 millert 494:
495: snprintf(cmd, sizeof(cmd), "cd %s; %s %s", dirname, value("LISTER"),
496: files && *files ? files : "");
497:
498: (void)run_command(value("SHELL"), 0, -1, -1, "-c", cmd, NULL);
1.6 millert 499: return(0);
500: }
501:
502: /*
503: * Update the mail file with any new messages that have
504: * come in since we started reading mail.
505: */
506: int
1.21 millert 507: inc(void *v)
1.6 millert 508: {
509: int nmsg, mdot;
510:
511: nmsg = incfile();
512:
513: if (nmsg == 0) {
514: puts("No new mail.");
515: } else if (nmsg > 0) {
516: mdot = newfileinfo(msgCount - nmsg);
517: dot = &message[mdot - 1];
518: } else {
519: puts("\"inc\" command failed...");
520: }
521:
522: return(0);
1.20 millert 523: }
524:
525: /*
526: * User hit ^C while printing the headers.
527: */
528: void
1.21 millert 529: hdrint(int s)
1.20 millert 530: {
531:
532: gothdrint = 1;
1.1 deraadt 533: }