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