Annotation of src/usr.bin/mail/cmd1.c, Revision 1.17
1.17 ! millert 1: /* $OpenBSD: cmd1.c,v 1.16 2000/06/30 16:00:18 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.17 ! millert 41: static char rcsid[] = "$OpenBSD: cmd1.c,v 1.16 2000/06/30 16:00:18 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;
347: char *cp;
1.1 deraadt 348: FILE *obuf;
1.17 ! millert 349:
1.3 deraadt 350: #if __GNUC__
1.8 millert 351: /* Avoid siglongjmp clobbering */
1.7 millert 352: (void)&cp;
353: (void)&obuf;
1.3 deraadt 354: #endif
1.1 deraadt 355:
356: obuf = stdout;
1.8 millert 357: if (sigsetjmp(pipestop, 1))
1.1 deraadt 358: goto close_pipe;
1.17 ! millert 359:
! 360: /*
! 361: * start a pipe if needed.
! 362: */
! 363: if (cmd) {
! 364: obuf = Popen(cmd, "w");
! 365: if (obuf == NULL) {
! 366: warn("%s", cp);
! 367: obuf = stdout;
! 368: } else {
! 369: (void)signal(SIGPIPE, brokpipe);
! 370: }
! 371: } else if (value("interactive") != NULL &&
! 372: (page || (cp = value("crt")) != NULL)) {
1.1 deraadt 373: nlines = 0;
374: if (!page) {
375: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
376: nlines += message[*ip - 1].m_lines;
377: }
378: if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
1.17 ! millert 379: obuf = Popen(value("PAGER"), "w");
1.1 deraadt 380: if (obuf == NULL) {
1.16 millert 381: warn("%s", cp);
1.1 deraadt 382: obuf = stdout;
383: } else
1.11 millert 384: (void)signal(SIGPIPE, brokpipe);
1.1 deraadt 385: }
386: }
1.17 ! millert 387:
! 388: /*
! 389: * send messages to the output.
! 390: */
1.1 deraadt 391: for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
392: mp = &message[*ip - 1];
393: touch(mp);
394: dot = mp;
1.17 ! millert 395: if (cmd == NULL && value("quiet") == NULL)
1.1 deraadt 396: fprintf(obuf, "Message %d:\n", *ip);
1.15 millert 397: (void)sendmessage(mp, obuf, doign ? ignore : 0, NULL);
1.1 deraadt 398: }
1.17 ! millert 399:
1.1 deraadt 400: close_pipe:
401: if (obuf != stdout) {
402: /*
403: * Ignore SIGPIPE so it can't cause a duplicate close.
404: */
1.11 millert 405: (void)signal(SIGPIPE, SIG_IGN);
1.6 millert 406: (void)Pclose(obuf);
1.11 millert 407: (void)signal(SIGPIPE, SIG_DFL);
1.1 deraadt 408: }
409: return(0);
410: }
411:
412: /*
413: * Respond to a broken pipe signal --
414: * probably caused by quitting more.
415: */
416: void
417: brokpipe(signo)
418: int signo;
419: {
1.8 millert 420: siglongjmp(pipestop, 1);
1.1 deraadt 421: }
422:
423: /*
424: * Print the top so many lines of each desired message.
425: * The number of lines is taken from the variable "toplines"
426: * and defaults to 5.
427: */
428: int
1.3 deraadt 429: top(v)
430: void *v;
1.1 deraadt 431: {
1.3 deraadt 432: int *msgvec = v;
1.12 millert 433: int *ip;
434: struct message *mp;
1.1 deraadt 435: int c, topl, lines, lineb;
436: char *valtop, linebuf[LINESIZE];
437: FILE *ibuf;
438:
439: topl = 5;
440: valtop = value("toplines");
1.8 millert 441: if (valtop != NULL) {
1.1 deraadt 442: topl = atoi(valtop);
443: if (topl < 0 || topl > 10000)
444: topl = 5;
445: }
446: lineb = 1;
447: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
448: mp = &message[*ip - 1];
449: touch(mp);
450: dot = mp;
1.8 millert 451: if (value("quiet") == NULL)
1.1 deraadt 452: printf("Message %d:\n", *ip);
453: ibuf = setinput(mp);
454: c = mp->m_lines;
455: if (!lineb)
1.6 millert 456: putchar('\n');
1.1 deraadt 457: for (lines = 0; lines < c && lines <= topl; lines++) {
1.9 millert 458: if (readline(ibuf, linebuf, sizeof(linebuf)) < 0)
1.1 deraadt 459: break;
460: puts(linebuf);
461: lineb = blankline(linebuf);
462: }
463: }
464: return(0);
465: }
466:
467: /*
468: * Touch all the given messages so that they will
469: * get mboxed.
470: */
471: int
1.3 deraadt 472: stouch(v)
473: void *v;
1.1 deraadt 474: {
1.3 deraadt 475: int *msgvec = v;
1.12 millert 476: int *ip;
1.1 deraadt 477:
478: for (ip = msgvec; *ip != 0; ip++) {
479: dot = &message[*ip-1];
480: dot->m_flag |= MTOUCH;
481: dot->m_flag &= ~MPRESERVE;
482: }
483: return(0);
484: }
485:
486: /*
487: * Make sure all passed messages get mboxed.
488: */
489: int
1.3 deraadt 490: mboxit(v)
491: void *v;
1.1 deraadt 492: {
1.3 deraadt 493: int *msgvec = v;
1.12 millert 494: int *ip;
1.1 deraadt 495:
496: for (ip = msgvec; *ip != 0; ip++) {
497: dot = &message[*ip-1];
498: dot->m_flag |= MTOUCH|MBOX;
499: dot->m_flag &= ~MPRESERVE;
500: }
501: return(0);
502: }
503:
504: /*
505: * List the folders the user currently has.
506: */
507: int
1.3 deraadt 508: folders(v)
509: void *v;
1.1 deraadt 510: {
1.17 ! millert 511: char *files = (char *)v;
1.5 deraadt 512: char dirname[PATHSIZE];
1.17 ! millert 513: char cmd[BUFSIZ];
1.1 deraadt 514:
1.6 millert 515: if (getfold(dirname, sizeof(dirname)) < 0) {
1.17 ! millert 516: strcpy(dirname, "$HOME");
1.1 deraadt 517: }
1.17 ! millert 518:
! 519: snprintf(cmd, sizeof(cmd), "cd %s; %s %s", dirname, value("LISTER"),
! 520: files && *files ? files : "");
! 521:
! 522: (void)run_command(value("SHELL"), 0, -1, -1, "-c", cmd, NULL);
1.6 millert 523: return(0);
524: }
525:
526: /*
527: * Update the mail file with any new messages that have
528: * come in since we started reading mail.
529: */
530: int
531: inc(v)
532: void *v;
533: {
534: int nmsg, mdot;
535:
536: nmsg = incfile();
537:
538: if (nmsg == 0) {
539: puts("No new mail.");
540: } else if (nmsg > 0) {
541: mdot = newfileinfo(msgCount - nmsg);
542: dot = &message[mdot - 1];
543: } else {
544: puts("\"inc\" command failed...");
545: }
546:
547: return(0);
1.1 deraadt 548: }