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