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