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