Annotation of src/usr.bin/msgs/msgs.c, Revision 1.32
1.32 ! chl 1: /* $OpenBSD: msgs.c,v 1.31 2007/05/17 10:59:26 moritz Exp $ */
1.1 deraadt 2: /* $NetBSD: msgs.c,v 1.7 1995/09/28 06:57:40 tls Exp $ */
3:
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.26 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
34: static char copyright[] =
35: "@(#) Copyright (c) 1980, 1993\n\
36: The Regents of the University of California. All rights reserved.\n";
37: #endif /* not lint */
38:
39: #ifndef lint
40: #if 0
41: static char sccsid[] = "@(#)msgs.c 8.2 (Berkeley) 4/28/95";
42: #else
1.32 ! chl 43: static char rcsid[] = "$OpenBSD: msgs.c,v 1.31 2007/05/17 10:59:26 moritz Exp $";
1.1 deraadt 44: #endif
45: #endif /* not lint */
46:
47: /*
48: * msgs - a user bulletin board program
49: *
50: * usage:
51: * msgs [fhlopqr] [[-]number] to read messages
52: * msgs -s to place messages
53: * msgs -c [-days] to clean up the bulletin board
54: *
55: * prompt commands are:
56: * y print message
57: * n flush message, go to next message
58: * q flush message, quit
59: * p print message, turn on 'pipe thru more' mode
60: * P print message, turn off 'pipe thru more' mode
61: * - reprint last message
62: * s[-][<num>] [<filename>] save message
63: * m[-][<num>] mail with message in temp mbox
64: * x exit without flushing this message
65: * <num> print message number <num>
66: */
67:
68: #define OBJECT /* will object to messages without Subjects */
69: #define REJECT /* will reject messages without Subjects
70: (OBJECT must be defined also) */
1.9 downsj 71: #undef UNBUFFERED /* use unbuffered output */
1.1 deraadt 72:
73: #include <sys/param.h>
74: #include <sys/ioctl.h>
75: #include <sys/stat.h>
76: #include <dirent.h>
77: #include <ctype.h>
1.32 ! chl 78: #include <err.h>
1.1 deraadt 79: #include <errno.h>
1.15 millert 80: #include <fcntl.h>
1.1 deraadt 81: #include <pwd.h>
82: #include <setjmp.h>
83: #include <signal.h>
84: #include <stdio.h>
85: #include <stdlib.h>
86: #include <string.h>
1.9 downsj 87: #include <term.h>
1.1 deraadt 88: #include <termios.h>
89: #include <time.h>
90: #include <unistd.h>
91: #include "pathnames.h"
92:
93: #define CMODE 0664 /* bounds file creation mode */
94: #define NO 0
95: #define YES 1
96: #define SUPERUSER 0 /* superuser uid */
97: #define DAEMON 1 /* daemon uid */
98: #define NLINES 24 /* default number of lines/crt screen */
99: #define NDAYS 21 /* default keep time for messages */
100: #define DAYS *24*60*60 /* seconds/day */
101: #define MSGSRC ".msgsrc" /* user's rc file */
102: #define BOUNDS "bounds" /* message bounds file */
103: #define NEXT "Next message? [yq]"
104: #define MORE "More? [ynq]"
105: #define NOMORE "(No more) [q] ?"
106:
107: typedef char bool;
108:
109: FILE *msgsrc;
110: FILE *newmsg;
111: char *sep = "-";
112: char inbuf[BUFSIZ];
1.8 deraadt 113: char fname[MAXPATHLEN];
114: char cmdbuf[MAXPATHLEN + MAXPATHLEN];
1.1 deraadt 115: char subj[128];
116: char from[128];
117: char date[128];
118: char *ptr;
119: char *in;
120: bool local;
121: bool ruptible;
122: bool totty;
123: bool seenfrom;
124: bool seensubj;
125: bool blankline;
126: bool printing = NO;
127: bool mailing = NO;
128: bool quitit = NO;
129: bool sending = NO;
130: bool intrpflg = NO;
131: bool restricted = NO;
132: int uid;
133: int msg;
134: int prevmsg;
135: int lct;
136: int nlines;
137: int Lpp = 0;
138: time_t t;
139: time_t keep;
140:
1.21 millert 141: void prmesg(int);
142: void onintr(int);
143: void onsusp(int);
144: int linecnt(FILE *);
1.24 deraadt 145: int next(char *, int);
1.21 millert 146: void ask(char *);
147: void gfrsub(FILE *);
148: char *nxtfld(char *);
1.1 deraadt 149:
150: /* option initialization */
151: bool hdrs = NO;
152: bool qopt = NO;
153: bool hush = NO;
154: bool send_msg = NO;
155: bool locomode = NO;
156: bool use_pager = NO;
157: bool clean = NO;
158: bool lastcmd = NO;
159: jmp_buf tstpbuf;
160:
1.9 downsj 161: int
1.27 deraadt 162: main(int argc, char *argv[])
1.1 deraadt 163: {
164: bool newrc, already;
165: int rcfirst = 0; /* first message to print (from .rc) */
166: int rcback = 0; /* amount to back off of rcfirst */
167: int firstmsg, nextmsg, lastmsg = 0;
168: int blast = 0;
169: FILE *bounds;
1.17 millert 170: char *cp;
1.1 deraadt 171:
172: #ifdef UNBUFFERED
173: setbuf(stdout, NULL);
174: #endif
175:
176: time(&t);
1.30 djm 177: uid = getuid();
178: if (setresuid(uid, uid, uid) == -1) {
179: perror("setresuid");
180: exit(1);
181: }
1.1 deraadt 182: ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL);
183: if (ruptible)
184: signal(SIGINT, SIG_DFL);
185:
186: argc--, argv++;
187: while (argc > 0) {
188: if (isdigit(argv[0][0])) { /* starting message # */
189: rcfirst = atoi(argv[0]);
1.29 deraadt 190: } else if (isdigit(argv[0][1])) { /* backward offset */
191: rcback = atoi(&(argv[0][1]));
192: } else {
1.1 deraadt 193: ptr = *argv;
1.29 deraadt 194: while (*ptr) {
195: switch (*ptr++) {
196: case '-':
197: break;
198: case 'c':
199: if (uid != SUPERUSER && uid != DAEMON) {
200: fprintf(stderr, "Sorry\n");
201: exit(1);
202: }
203: clean = YES;
204: break;
205: case 'f': /* silently */
206: hush = YES;
207: break;
208: case 'h': /* headers only */
209: hdrs = YES;
210: break;
211: case 'l': /* local msgs only */
212: locomode = YES;
213: break;
214: case 'o': /* option to save last message */
215: lastcmd = YES;
216: break;
217: case 'p': /* pipe thru 'more' during long msgs */
218: use_pager = YES;
219: break;
220: case 'q': /* query only */
221: qopt = YES;
222: break;
223: case 'r': /* restricted */
224: restricted = YES;
225: break;
226: case 's': /* sending TO msgs */
227: send_msg = YES;
228: break;
229: default:
230: fprintf(stderr,
231: "usage: msgs [fhlopqr] [[-]number]\n"
232: " msgs [-s]\n"
233: " msgs [-c [-days]]\n");
1.1 deraadt 234: exit(1);
235: }
236: }
237: }
238: argc--, argv++;
239: }
240:
241: /*
242: * determine current message bounds
243: */
1.5 millert 244: snprintf(fname, sizeof(fname), "%s/%s", _PATH_MSGS, BOUNDS);
1.1 deraadt 245: bounds = fopen(fname, "r");
246:
1.12 deraadt 247: if (bounds == NULL) {
1.13 aaron 248: if (errno == ENOENT) {
249: if ((bounds = fopen(fname, "w+")) == NULL) {
250: perror(fname);
251: exit(1);
252: }
253: fprintf(bounds, "1 0\n");
254: rewind(bounds);
1.29 deraadt 255: } else {
1.13 aaron 256: perror(fname);
257: exit(1);
258: }
1.1 deraadt 259: }
1.12 deraadt 260:
261: fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg);
262: fclose(bounds);
263: blast = lastmsg; /* save upper bound */
1.1 deraadt 264:
265: if (clean)
266: keep = t - (rcback? rcback : NDAYS) DAYS;
267:
268: if (clean || bounds == NULL) { /* relocate message bounds */
269: struct dirent *dp;
270: struct stat stbuf;
271: bool seenany = NO;
272: DIR *dirp;
273:
274: dirp = opendir(_PATH_MSGS);
275: if (dirp == NULL) {
276: perror(_PATH_MSGS);
277: exit(errno);
278: }
279: chmod(fname, CMODE);
280:
281: firstmsg = 32767;
282: lastmsg = 0;
283:
284: for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){
1.19 mpech 285: int i = 0;
1.1 deraadt 286:
1.17 millert 287: cp = dp->d_name;
1.1 deraadt 288: if (dp->d_ino == 0)
289: continue;
290: if (dp->d_namlen == 0)
291: continue;
292:
293: if (clean)
1.5 millert 294: snprintf(inbuf, sizeof(inbuf), "%s/%s",
1.29 deraadt 295: _PATH_MSGS, cp);
1.1 deraadt 296:
297: while (isdigit(*cp))
298: i = i * 10 + *cp++ - '0';
299: if (*cp)
300: continue; /* not a message! */
301:
302: if (clean) {
303: if (stat(inbuf, &stbuf) != 0)
304: continue;
1.29 deraadt 305: if (stbuf.st_mtime < keep &&
306: stbuf.st_mode&S_IWRITE) {
1.1 deraadt 307: unlink(inbuf);
308: continue;
309: }
310: }
311:
312: if (i > lastmsg)
313: lastmsg = i;
314: if (i < firstmsg)
315: firstmsg = i;
316: seenany = YES;
317: }
318: closedir(dirp);
319:
320: if (!seenany) {
321: if (blast != 0) /* never lower the upper bound! */
322: lastmsg = blast;
323: firstmsg = lastmsg + 1;
1.29 deraadt 324: } else if (blast > lastmsg)
1.1 deraadt 325: lastmsg = blast;
326:
327: if (!send_msg) {
328: bounds = fopen(fname, "w");
329: if (bounds == NULL) {
330: perror(fname);
331: exit(errno);
332: }
333: chmod(fname, CMODE);
334: fprintf(bounds, "%d %d\n", firstmsg, lastmsg);
335: fclose(bounds);
336: }
337: }
338:
339: if (send_msg) {
340: /*
341: * Send mode - place msgs in _PATH_MSGS
342: */
343: bounds = fopen(fname, "w");
344: if (bounds == NULL) {
345: perror(fname);
346: exit(errno);
347: }
348:
349: nextmsg = lastmsg + 1;
1.5 millert 350: snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, nextmsg);
1.1 deraadt 351: newmsg = fopen(fname, "w");
352: if (newmsg == NULL) {
353: perror(fname);
354: exit(errno);
355: }
356: chmod(fname, 0644);
357:
358: fprintf(bounds, "%d %d\n", firstmsg, nextmsg);
359: fclose(bounds);
360:
361: sending = YES;
362: if (ruptible)
363: signal(SIGINT, onintr);
364:
365: if (isatty(fileno(stdin))) {
1.31 moritz 366: struct passwd *pw;
367:
368: if ((pw = getpwuid(uid)) == NULL) {
369: perror("getpwuid");
370: exit(1);
371: }
1.1 deraadt 372: printf("Message %d:\nFrom %s %sSubject: ",
1.31 moritz 373: nextmsg, pw->pw_name, ctime(&t));
1.1 deraadt 374: fflush(stdout);
1.32 ! chl 375: if (fgets(inbuf, sizeof inbuf, stdin) == NULL)
! 376: errx(1, "could not read input");
1.1 deraadt 377: putchar('\n');
378: fflush(stdout);
379: fprintf(newmsg, "From %s %sSubject: %s\n",
1.31 moritz 380: pw->pw_name, ctime(&t), inbuf);
1.1 deraadt 381: blankline = seensubj = YES;
1.29 deraadt 382: } else
1.1 deraadt 383: blankline = seensubj = NO;
384: for (;;) {
1.32 ! chl 385: if (fgets(inbuf, sizeof inbuf, stdin) == NULL)
1.1 deraadt 386: break;
387: blankline = (blankline || (inbuf[0] == '\n'));
1.29 deraadt 388: seensubj = (seensubj ||
389: (!blankline && (strncmp(inbuf, "Subj", 4) == 0)));
1.1 deraadt 390: fputs(inbuf, newmsg);
391: }
392: #ifdef OBJECT
393: if (!seensubj) {
394: printf("NOTICE: Messages should have a Subject field!\n");
395: #ifdef REJECT
396: unlink(fname);
397: #endif
398: exit(1);
399: }
400: #endif
401: exit(ferror(stdin));
402: }
403: if (clean)
404: exit(0);
405:
406: /*
407: * prepare to display messages
408: */
409: totty = (isatty(fileno(stdout)) != 0);
410: use_pager = use_pager && totty;
411:
1.17 millert 412: if ((cp = getenv("HOME")) == NULL || *cp == '\0') {
413: fprintf(stderr, "Error, no home directory!\n");
414: exit(1);
415: }
416: snprintf(fname, sizeof(fname), "%s/%s", cp, MSGSRC);
1.1 deraadt 417: msgsrc = fopen(fname, "r");
418: if (msgsrc) {
419: newrc = NO;
1.11 deraadt 420: fscanf(msgsrc, "%d\n", &nextmsg);
421: fclose(msgsrc);
422: if (nextmsg > lastmsg+1) {
1.1 deraadt 423: printf("Warning: bounds have been reset (%d, %d)\n",
1.29 deraadt 424: firstmsg, lastmsg);
1.1 deraadt 425: truncate(fname, (off_t)0);
426: newrc = YES;
1.29 deraadt 427: } else if (!rcfirst)
1.1 deraadt 428: rcfirst = nextmsg - rcback;
1.29 deraadt 429: } else
1.11 deraadt 430: newrc = YES;
431: msgsrc = fopen(fname, "r+");
432: if (msgsrc == NULL)
433: msgsrc = fopen(fname, "w");
1.1 deraadt 434: if (msgsrc == NULL) {
435: perror(fname);
436: exit(errno);
437: }
438: if (rcfirst) {
439: if (rcfirst > lastmsg+1) {
440: printf("Warning: the last message is number %d.\n",
1.29 deraadt 441: lastmsg);
1.1 deraadt 442: rcfirst = nextmsg;
443: }
444: if (rcfirst > firstmsg)
445: firstmsg = rcfirst; /* don't set below first msg */
446: }
447: if (newrc) {
448: nextmsg = firstmsg;
1.29 deraadt 449: fseeko(msgsrc, (off_t)0, SEEK_SET);
1.1 deraadt 450: fprintf(msgsrc, "%d\n", nextmsg);
451: fflush(msgsrc);
452: }
453:
454: if (totty) {
455: struct winsize win;
456: if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1)
457: Lpp = win.ws_row;
458: if (Lpp <= 0) {
1.10 downsj 459: char *ttype = getenv("TERM");
460:
461: if (ttype != (char *)NULL) {
462: if (tgetent(NULL, ttype) <= 0
463: || (Lpp = tgetnum("li")) <= 0) {
464: Lpp = NLINES;
465: }
466: } else
1.1 deraadt 467: Lpp = NLINES;
468: }
469: }
470: Lpp -= 6; /* for headers, etc. */
471:
472: already = NO;
473: prevmsg = firstmsg;
474: printing = YES;
475: if (ruptible)
476: signal(SIGINT, onintr);
477:
478: /*
479: * Main program loop
480: */
481: for (msg = firstmsg; msg <= lastmsg; msg++) {
482:
1.5 millert 483: snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, msg);
1.1 deraadt 484: newmsg = fopen(fname, "r");
485: if (newmsg == NULL)
486: continue;
487:
488: gfrsub(newmsg); /* get From and Subject fields */
489: if (locomode && !local) {
490: fclose(newmsg);
491: continue;
492: }
493:
494: if (qopt) { /* This has to be located here */
495: printf("There are new messages.\n");
496: exit(0);
497: }
498:
499: if (already && !hdrs)
500: putchar('\n');
501:
502: /*
503: * Print header
504: */
505: if (totty)
506: signal(SIGTSTP, onsusp);
507: (void) setjmp(tstpbuf);
508: already = YES;
509: nlines = 2;
510: if (seenfrom) {
511: printf("Message %d:\nFrom %s %s", msg, from, date);
512: nlines++;
513: }
514: if (seensubj) {
515: printf("Subject: %s", subj);
516: nlines++;
1.29 deraadt 517: } else {
1.1 deraadt 518: if (seenfrom) {
519: putchar('\n');
520: nlines++;
521: }
1.29 deraadt 522: while (nlines < 6 &&
523: fgets(inbuf, sizeof inbuf, newmsg) &&
524: inbuf[0] != '\n') {
1.1 deraadt 525: fputs(inbuf, stdout);
526: nlines++;
527: }
528: }
529:
530: lct = linecnt(newmsg);
531: if (lct)
532: printf("(%d%slines) ", lct, seensubj? " " : " more ");
533:
534: if (hdrs) {
535: printf("\n-----\n");
536: fclose(newmsg);
537: continue;
538: }
539:
540: /*
541: * Ask user for command
542: */
543: if (totty)
544: ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT));
545: else
546: inbuf[0] = 'y';
547: if (totty)
548: signal(SIGTSTP, SIG_DFL);
549: cmnd:
550: in = inbuf;
551: switch (*in) {
1.29 deraadt 552: case 'x':
553: case 'X':
554: exit(0);
1.1 deraadt 555:
1.29 deraadt 556: case 'q':
557: case 'Q':
558: quitit = YES;
559: printf("--Postponed--\n");
560: exit(0);
561: /* intentional fall-thru */
562: case 'n':
563: case 'N':
564: if (msg >= nextmsg)
565: sep = "Flushed";
566: prevmsg = msg;
567: break;
1.1 deraadt 568:
1.29 deraadt 569: case 'p':
570: case 'P':
571: use_pager = (*in++ == 'p');
572: /* intentional fallthru */
573: case '\n':
574: case 'y':
575: default:
576: if (*in == '-') {
577: msg = prevmsg-1;
578: sep = "replay";
579: break;
580: }
581: if (isdigit(*in)) {
582: msg = next(in, sizeof inbuf);
583: sep = in;
584: break;
585: }
1.1 deraadt 586:
1.29 deraadt 587: prmesg(nlines + lct + (seensubj? 1 : 0));
588: prevmsg = msg;
1.1 deraadt 589: }
590:
591: printf("--%s--\n", sep);
592: sep = "-";
593: if (msg >= nextmsg) {
594: nextmsg = msg + 1;
1.29 deraadt 595: fseeko(msgsrc, (off_t)0, SEEK_SET);
1.1 deraadt 596: fprintf(msgsrc, "%d\n", nextmsg);
597: fflush(msgsrc);
598: }
599: if (newmsg)
600: fclose(newmsg);
601: if (quitit)
602: break;
603: }
604:
605: /*
606: * Make sure .rc file gets updated
607: */
608: if (--msg >= nextmsg) {
609: nextmsg = msg + 1;
1.29 deraadt 610: fseeko(msgsrc, (off_t)0, SEEK_SET);
1.1 deraadt 611: fprintf(msgsrc, "%d\n", nextmsg);
612: fflush(msgsrc);
613: }
614: if (already && !quitit && lastcmd && totty) {
615: /*
616: * save or reply to last message?
617: */
618: msg = prevmsg;
619: ask(NOMORE);
620: if (inbuf[0] == '-' || isdigit(inbuf[0]))
621: goto cmnd;
622: }
623: if (!(already || hush || qopt))
624: printf("No new messages.\n");
625: exit(0);
626: }
627:
1.9 downsj 628: void
1.27 deraadt 629: prmesg(int length)
1.1 deraadt 630: {
631: FILE *outf;
632: char *env_pager;
633:
634: if (use_pager && length > Lpp) {
635: signal(SIGPIPE, SIG_IGN);
636: signal(SIGQUIT, SIG_IGN);
1.14 pjanzen 637: if ((env_pager = getenv("PAGER")) == NULL || *env_pager == '\0') {
1.11 deraadt 638: snprintf(cmdbuf, sizeof(cmdbuf), _PATH_PAGER, Lpp);
639: } else {
1.16 deraadt 640: snprintf(cmdbuf, sizeof(cmdbuf), "%s", env_pager);
1.11 deraadt 641: }
1.1 deraadt 642: outf = popen(cmdbuf, "w");
643: if (!outf)
644: outf = stdout;
645: else
646: setbuf(outf, (char *)NULL);
647: }
648: else
649: outf = stdout;
650:
651: if (seensubj)
652: putc('\n', outf);
653:
654: while (fgets(inbuf, sizeof inbuf, newmsg)) {
655: fputs(inbuf, outf);
656: if (ferror(outf)) {
657: clearerr(outf);
658: break;
659: }
660: }
661:
662: if (outf != stdout) {
663: pclose(outf);
664: signal(SIGPIPE, SIG_DFL);
665: signal(SIGQUIT, SIG_DFL);
1.29 deraadt 666: } else {
1.1 deraadt 667: fflush(stdout);
668: }
669:
670: /* trick to force wait on output */
671: tcdrain(fileno(stdout));
672: }
673:
1.29 deraadt 674: /* ARGSUSED */
1.1 deraadt 675: void
1.29 deraadt 676: onintr(int signo)
1.1 deraadt 677: {
1.29 deraadt 678: int save_errno = errno;
679:
1.1 deraadt 680: signal(SIGINT, onintr);
681: if (mailing)
682: unlink(fname);
683: if (sending) {
684: unlink(fname);
1.29 deraadt 685: write(STDOUT_FILENO, "--Killed--\n", strlen("--Killed--\n"));
686: _exit(1);
1.1 deraadt 687: }
688: if (printing) {
1.29 deraadt 689: write(STDOUT_FILENO, "\n", 1);
1.1 deraadt 690: if (hdrs)
1.29 deraadt 691: _exit(0);
1.1 deraadt 692: sep = "Interrupt";
693: if (newmsg)
1.29 deraadt 694: fseeko(newmsg, (off_t)0, SEEK_END);
1.1 deraadt 695: intrpflg = YES;
696: }
1.29 deraadt 697: errno = save_errno;
1.1 deraadt 698: }
699:
700: /*
701: * We have just gotten a susp. Suspend and prepare to resume.
702: */
1.29 deraadt 703: /* ARGSUSED */
1.1 deraadt 704: void
1.29 deraadt 705: onsusp(int signo)
1.1 deraadt 706: {
1.29 deraadt 707: int save_errno = errno;
1.18 millert 708: sigset_t emptyset;
709:
1.1 deraadt 710: signal(SIGTSTP, SIG_DFL);
1.18 millert 711: sigemptyset(&emptyset);
712: sigprocmask(SIG_SETMASK, &emptyset, NULL);
1.1 deraadt 713: kill(0, SIGTSTP);
714: signal(SIGTSTP, onsusp);
1.29 deraadt 715: errno = save_errno;
716:
1.1 deraadt 717: if (!mailing)
1.20 art 718: longjmp(tstpbuf, 1);
1.1 deraadt 719: }
720:
1.9 downsj 721: int
1.27 deraadt 722: linecnt(FILE *f)
1.1 deraadt 723: {
1.29 deraadt 724: off_t oldpos = ftello(f);
725:
1.1 deraadt 726: int l = 0;
727: char lbuf[BUFSIZ];
728:
729: while (fgets(lbuf, sizeof lbuf, f))
730: l++;
731: clearerr(f);
1.29 deraadt 732: fseeko(f, oldpos, SEEK_SET);
1.1 deraadt 733: return (l);
734: }
735:
1.9 downsj 736: int
1.27 deraadt 737: next(char *buf, int len)
1.1 deraadt 738: {
739: int i;
740: sscanf(buf, "%d", &i);
1.24 deraadt 741: snprintf(buf, len, "Goto %d", i);
1.1 deraadt 742: return(--i);
743: }
744:
1.9 downsj 745: void
1.27 deraadt 746: ask(char *prompt)
1.1 deraadt 747: {
748: char inch;
1.2 deraadt 749: int n, cmsg, fd;
1.1 deraadt 750: off_t oldpos;
751: FILE *cpfrom, *cpto;
752:
753: printf("%s ", prompt);
754: fflush(stdout);
755: intrpflg = NO;
1.32 ! chl 756: if (fgets(inbuf, sizeof inbuf, stdin) == NULL)
! 757: errx(1, "could not read input");
! 758: inbuf[strcspn(inbuf, "\n")] = '\0';
1.1 deraadt 759: if (intrpflg)
760: inbuf[0] = 'x';
761:
762: /*
763: * Handle 'mail' and 'save' here.
764: */
1.11 deraadt 765: if (((inch = inbuf[0]) == 's' || inch == 'm') && !restricted) {
1.1 deraadt 766: if (inbuf[1] == '-')
767: cmsg = prevmsg;
768: else if (isdigit(inbuf[1]))
769: cmsg = atoi(&inbuf[1]);
770: else
771: cmsg = msg;
1.5 millert 772: snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, cmsg);
1.1 deraadt 773:
1.29 deraadt 774: oldpos = ftello(newmsg);
1.1 deraadt 775:
776: cpfrom = fopen(fname, "r");
777: if (!cpfrom) {
778: printf("Message %d not found\n", cmsg);
779: ask (prompt);
780: return;
781: }
782:
783: if (inch == 's') {
784: in = nxtfld(inbuf);
785: if (*in) {
1.22 ho 786: for (n=0;
1.29 deraadt 787: in[n] > ' ' && n < sizeof fname - 1;
788: n++) {
1.1 deraadt 789: fname[n] = in[n];
790: }
791: fname[n] = NULL;
792: }
793: else
1.25 deraadt 794: strlcpy(fname, "Messages", sizeof fname);
1.22 ho 795: fd = open(fname, O_RDWR|O_EXCL|O_CREAT|O_APPEND, 0666);
1.29 deraadt 796: } else {
1.25 deraadt 797: strlcpy(fname, _PATH_TMPFILE, sizeof fname);
1.7 deraadt 798: fd = mkstemp(fname);
799: if (fd != -1) {
800: snprintf(cmdbuf, sizeof(cmdbuf), _PATH_MAIL, fname);
801: mailing = YES;
802: }
803: }
804: if (fd == -1 || (cpto = fdopen(fd, "a")) == NULL) {
805: if (fd != -1)
1.2 deraadt 806: close(fd);
1.1 deraadt 807: perror(fname);
808: mailing = NO;
1.29 deraadt 809: fseeko(newmsg, oldpos, SEEK_SET);
1.1 deraadt 810: ask(prompt);
811: return;
812: }
813:
1.9 downsj 814: while ((n = fread(inbuf, 1, sizeof inbuf, cpfrom)))
1.1 deraadt 815: fwrite(inbuf, 1, n, cpto);
816:
817: fclose(cpfrom);
818: fclose(cpto);
1.29 deraadt 819: fseeko(newmsg, oldpos, SEEK_SET); /* reposition current message */
1.1 deraadt 820: if (inch == 's')
821: printf("Message %d saved in \"%s\"\n", cmsg, fname);
822: else {
823: system(cmdbuf);
824: unlink(fname);
825: mailing = NO;
826: }
827: ask(prompt);
828: }
829: }
830:
1.9 downsj 831: void
1.27 deraadt 832: gfrsub(FILE *infile)
1.1 deraadt 833: {
834: off_t frompos;
835:
836: seensubj = seenfrom = NO;
837: local = YES;
838: subj[0] = from[0] = date[0] = NULL;
839:
840: /*
841: * Is this a normal message?
842: */
843: if (fgets(inbuf, sizeof inbuf, infile)) {
844: if (strncmp(inbuf, "From", 4)==0) {
845: /*
846: * expected form starts with From
847: */
848: seenfrom = YES;
1.29 deraadt 849: frompos = ftello(infile);
1.1 deraadt 850: ptr = from;
851: in = nxtfld(inbuf);
1.8 deraadt 852: if (*in) {
853: while (*in && *in > ' ' &&
854: ptr - from < sizeof from -1) {
855: if (*in == ':' || *in == '@' || *in == '!')
856: local = NO;
857: *ptr++ = *in++;
858: }
1.1 deraadt 859: }
860: *ptr = NULL;
861: if (*(in = nxtfld(in)))
862: strncpy(date, in, sizeof date);
863: else {
864: date[0] = '\n';
865: date[1] = NULL;
866: }
1.29 deraadt 867: } else {
1.1 deraadt 868: /*
869: * not the expected form
870: */
1.29 deraadt 871: fseeko(infile, (off_t)0, SEEK_SET);
1.1 deraadt 872: return;
873: }
1.29 deraadt 874: } else
1.1 deraadt 875: /*
876: * empty file ?
877: */
878: return;
879:
880: /*
881: * look for Subject line until EOF or a blank line
882: */
1.29 deraadt 883: while (fgets(inbuf, sizeof inbuf, infile) &&
884: !(blankline = (inbuf[0] == '\n'))) {
1.1 deraadt 885: /*
886: * extract Subject line
887: */
888: if (!seensubj && strncmp(inbuf, "Subj", 4)==0) {
889: seensubj = YES;
1.29 deraadt 890: frompos = ftello(infile);
1.1 deraadt 891: strncpy(subj, nxtfld(inbuf), sizeof subj);
892: }
893: }
894: if (!blankline)
895: /*
896: * ran into EOF
897: */
1.29 deraadt 898: fseeko(infile, frompos, SEEK_SET);
1.1 deraadt 899:
900: if (!seensubj)
901: /*
902: * for possible use with Mail
903: */
904: strncpy(subj, "(No Subject)\n", sizeof subj);
905: }
906:
907: char *
1.27 deraadt 908: nxtfld(char *s)
1.1 deraadt 909: {
1.29 deraadt 910: if (*s)
911: while (*s && *s > ' ')
912: s++; /* skip over this field */
913: if (*s)
914: while (*s && *s <= ' ')
915: s++; /* find start of next field */
1.1 deraadt 916: return (s);
917: }