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