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