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