msgs.c revision 1.12 1 /* $NetBSD: msgs.c,v 1.12 1998/07/26 22:14:34 mycroft 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 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) 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 __RCSID("$NetBSD: msgs.c,v 1.12 1998/07/26 22:14:34 mycroft 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 <ctype.h>
81 #include <dirent.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 <termcap.h>
90 #include <termios.h>
91 #include <time.h>
92 #include <unistd.h>
93 #include "pathnames.h"
94
95 #define CMODE 0664 /* bounds file creation mode */
96 #define NO 0
97 #define YES 1
98 #define SUPERUSER 0 /* superuser uid */
99 #define DAEMON 1 /* daemon uid */
100 #define NLINES 24 /* default number of lines/crt screen */
101 #define NDAYS 21 /* default keep time for messages */
102 #define DAYS *24*60*60 /* seconds/day */
103 #define MSGSRC ".msgsrc" /* user's rc file */
104 #define BOUNDS "bounds" /* message bounds file */
105 #define NEXT "Next message? [yq]"
106 #define MORE "More? [ynq]"
107 #define NOMORE "(No more) [q] ?"
108
109 typedef char bool;
110
111 FILE *msgsrc;
112 FILE *newmsg;
113 char *sep = "-";
114 char inbuf[BUFSIZ];
115 char fname[128];
116 char cmdbuf[128];
117 char subj[128];
118 char from[128];
119 char date[128];
120 char *ptr;
121 char *in;
122 bool local;
123 bool ruptible;
124 bool totty;
125 bool seenfrom;
126 bool seensubj;
127 bool blankline;
128 bool printing = NO;
129 bool mailing = NO;
130 bool quitit = NO;
131 bool sending = NO;
132 bool intrpflg = NO;
133 bool restricted = NO;
134 int uid;
135 int msg;
136 int prevmsg;
137 int lct;
138 int nlines;
139 int Lpp = 0;
140 time_t t;
141 time_t keep;
142
143 void ask __P((char *));
144 void gfrsub __P((FILE *));
145 int linecnt __P((FILE *));
146 int main __P((int, char *[]));
147 int next __P((char *));
148 char *nxtfld __P((char *));
149 void onintr __P((int));
150 void onsusp __P((int));
151 void prmesg __P((int));
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
164 int
165 main(argc, argv)
166 int argc; char *argv[];
167 {
168 bool newrc, already;
169 int rcfirst = 0; /* first message to print (from .rc) */
170 int rcback = 0; /* amount to back off of rcfirst */
171 int firstmsg, nextmsg, lastmsg = 0;
172 int blast = 0;
173 FILE *bounds;
174 struct passwd *pw;
175
176 #ifdef UNBUFFERED
177 setbuf(stdout, NULL);
178 #endif
179
180 time(&t);
181 setuid(uid = getuid());
182 ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL);
183 if (ruptible)
184 signal(SIGINT, SIG_DFL);
185
186 argc--, argv++;
187 while (argc > 0) {
188 if (isdigit(argv[0][0])) { /* starting message # */
189 rcfirst = atoi(argv[0]);
190 }
191 else if (isdigit(argv[0][1])) { /* backward offset */
192 rcback = atoi( &( argv[0][1] ) );
193 }
194 else {
195 ptr = *argv;
196 while (*ptr) switch (*ptr++) {
197
198 case '-':
199 break;
200
201 case 'c':
202 if (uid != SUPERUSER && uid != DAEMON) {
203 fprintf(stderr, "Sorry\n");
204 exit(1);
205 }
206 clean = YES;
207 break;
208
209 case 'f': /* silently */
210 hush = YES;
211 break;
212
213 case 'h': /* headers only */
214 hdrs = YES;
215 break;
216
217 case 'l': /* local msgs only */
218 locomode = YES;
219 break;
220
221 case 'o': /* option to save last message */
222 lastcmd = YES;
223 break;
224
225 case 'p': /* pipe thru 'more' during long msgs */
226 use_pager = YES;
227 break;
228
229 case 'q': /* query only */
230 qopt = YES;
231 break;
232
233 case 'r': /* restricted */
234 restricted = YES;
235 break;
236
237
238 case 's': /* sending TO msgs */
239 send_msg = YES;
240 break;
241
242 default:
243 fprintf(stderr,
244 "usage: msgs [fhlopqr] [[-]number]\n");
245 exit(1);
246 }
247 }
248 argc--, argv++;
249 }
250
251 /*
252 * determine current message bounds
253 */
254 sprintf(fname, "%s/%s", _PATH_MSGS, BOUNDS);
255 bounds = fopen(fname, "r");
256
257 if (bounds != NULL) {
258 if (fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg) < 2)
259 firstmsg = lastmsg = 0;
260 fclose(bounds);
261 blast = lastmsg; /* save upper bound */
262 }
263
264 if (clean)
265 keep = t - (rcback? rcback : NDAYS) DAYS;
266
267 if (clean || bounds == NULL) { /* relocate message bounds */
268 struct dirent *dp;
269 struct stat stbuf;
270 bool seenany = NO;
271 DIR *dirp;
272
273 dirp = opendir(_PATH_MSGS);
274 if (dirp == NULL) {
275 perror(_PATH_MSGS);
276 exit(errno);
277 }
278 chmod(fname, CMODE);
279
280 firstmsg = 32767;
281 lastmsg = 0;
282
283 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){
284 char *cp = dp->d_name;
285 int i = 0;
286
287 if (dp->d_ino == 0)
288 continue;
289 if (dp->d_namlen == 0)
290 continue;
291
292 if (clean)
293 sprintf(inbuf, "%s/%s", _PATH_MSGS, cp);
294
295 while (isdigit(*cp))
296 i = i * 10 + *cp++ - '0';
297 if (*cp)
298 continue; /* not a message! */
299
300 if (clean) {
301 if (stat(inbuf, &stbuf) != 0)
302 continue;
303 if (stbuf.st_mtime < keep
304 && stbuf.st_mode&S_IWRITE) {
305 unlink(inbuf);
306 continue;
307 }
308 }
309
310 if (i > lastmsg)
311 lastmsg = i;
312 if (i < firstmsg)
313 firstmsg = i;
314 seenany = YES;
315 }
316 closedir(dirp);
317
318 if (!seenany) {
319 if (blast != 0) /* never lower the upper bound! */
320 lastmsg = blast;
321 firstmsg = lastmsg + 1;
322 }
323 else if (blast > lastmsg)
324 lastmsg = blast;
325
326 if (!send_msg) {
327 bounds = fopen(fname, "w");
328 if (bounds == NULL) {
329 perror(fname);
330 exit(errno);
331 }
332 chmod(fname, CMODE);
333 fprintf(bounds, "%d %d\n", firstmsg, lastmsg);
334 fclose(bounds);
335 }
336 }
337
338 if (send_msg) {
339 /*
340 * Send mode - place msgs in _PATH_MSGS
341 */
342 bounds = fopen(fname, "w");
343 if (bounds == NULL) {
344 perror(fname);
345 exit(errno);
346 }
347
348 nextmsg = lastmsg + 1;
349 sprintf(fname, "%s/%d", _PATH_MSGS, nextmsg);
350 newmsg = fopen(fname, "w");
351 if (newmsg == NULL) {
352 perror(fname);
353 exit(errno);
354 }
355 chmod(fname, 0644);
356
357 fprintf(bounds, "%d %d\n", firstmsg, nextmsg);
358 fclose(bounds);
359
360 sending = YES;
361 if (ruptible)
362 signal(SIGINT, onintr);
363
364 if (isatty(fileno(stdin))) {
365 pw = getpwuid(uid);
366 if (!pw) {
367 fprintf(stderr, "Who are you?\n");
368 exit(1);
369 }
370 printf("Message %d:\nFrom %s %sSubject: ",
371 nextmsg, pw->pw_name, 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
410 sprintf(fname, "%s/%s", getenv("HOME"), MSGSRC);
411 msgsrc = fopen(fname, "r");
412 if (msgsrc) {
413 newrc = NO;
414 fscanf(msgsrc, "%d\n", &nextmsg);
415 fclose(msgsrc);
416 if (nextmsg > lastmsg+1) {
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 }
425 else
426 newrc = YES;
427 msgsrc = fopen(fname, "r+");
428 if (msgsrc == NULL)
429 msgsrc = fopen(fname, "w");
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 #ifdef V7
451 if (totty) {
452 struct winsize win;
453 if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1)
454 Lpp = win.ws_row;
455 if (Lpp <= 0) {
456 if (tgetent(inbuf, getenv("TERM")) <= 0
457 || (Lpp = tgetnum("li")) <= 0) {
458 Lpp = NLINES;
459 }
460 }
461 }
462 #endif
463 Lpp -= 6; /* for headers, etc. */
464
465 already = NO;
466 prevmsg = firstmsg;
467 printing = YES;
468 if (ruptible)
469 signal(SIGINT, onintr);
470
471 /*
472 * Main program loop
473 */
474 for (msg = firstmsg; msg <= lastmsg; msg++) {
475
476 sprintf(fname, "%s/%d", _PATH_MSGS, msg);
477 newmsg = fopen(fname, "r");
478 if (newmsg == NULL)
479 continue;
480
481 gfrsub(newmsg); /* get From and Subject fields */
482 if (locomode && !local) {
483 fclose(newmsg);
484 continue;
485 }
486
487 if (qopt) { /* This has to be located here */
488 printf("There are new messages.\n");
489 exit(0);
490 }
491
492 if (already && !hdrs)
493 putchar('\n');
494
495 /*
496 * Print header
497 */
498 if (totty)
499 signal(SIGTSTP, onsusp);
500 (void) setjmp(tstpbuf);
501 already = YES;
502 nlines = 2;
503 if (seenfrom) {
504 printf("Message %d:\nFrom %s %s", msg, from, date);
505 nlines++;
506 }
507 if (seensubj) {
508 printf("Subject: %s", subj);
509 nlines++;
510 }
511 else {
512 if (seenfrom) {
513 putchar('\n');
514 nlines++;
515 }
516 while (nlines < 6
517 && fgets(inbuf, sizeof inbuf, newmsg)
518 && inbuf[0] != '\n') {
519 fputs(inbuf, stdout);
520 nlines++;
521 }
522 }
523
524 lct = linecnt(newmsg);
525 if (lct)
526 printf("(%d%slines) ", lct, seensubj? " " : " more ");
527
528 if (hdrs) {
529 printf("\n-----\n");
530 fclose(newmsg);
531 continue;
532 }
533
534 /*
535 * Ask user for command
536 */
537 if (totty)
538 ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT));
539 else
540 inbuf[0] = 'y';
541 if (totty)
542 signal(SIGTSTP, SIG_DFL);
543 cmnd:
544 in = inbuf;
545 switch (*in) {
546 case 'x':
547 case 'X':
548 exit(0);
549
550 case 'q':
551 case 'Q':
552 quitit = YES;
553 printf("--Postponed--\n");
554 exit(0);
555 /* intentional fall-thru */
556 case 'n':
557 case 'N':
558 if (msg >= nextmsg) sep = "Flushed";
559 prevmsg = msg;
560 break;
561
562 case 'p':
563 case 'P':
564 use_pager = (*in++ == 'p');
565 /* intentional fallthru */
566 case '\n':
567 case 'y':
568 default:
569 if (*in == '-') {
570 msg = prevmsg-1;
571 sep = "replay";
572 break;
573 }
574 if (isdigit(*in)) {
575 msg = next(in);
576 sep = in;
577 break;
578 }
579
580 prmesg(nlines + lct + (seensubj? 1 : 0));
581 prevmsg = msg;
582
583 }
584
585 printf("--%s--\n", sep);
586 sep = "-";
587 if (msg >= nextmsg) {
588 nextmsg = msg + 1;
589 fseek(msgsrc, 0L, 0);
590 fprintf(msgsrc, "%d\n", nextmsg);
591 fflush(msgsrc);
592 }
593 if (newmsg)
594 fclose(newmsg);
595 if (quitit)
596 break;
597 }
598
599 /*
600 * Make sure .rc file gets updated
601 */
602 if (--msg >= nextmsg) {
603 nextmsg = msg + 1;
604 fseek(msgsrc, 0L, 0);
605 fprintf(msgsrc, "%d\n", nextmsg);
606 fflush(msgsrc);
607 }
608 if (already && !quitit && lastcmd && totty) {
609 /*
610 * save or reply to last message?
611 */
612 msg = prevmsg;
613 ask(NOMORE);
614 if (inbuf[0] == '-' || isdigit(inbuf[0]))
615 goto cmnd;
616 }
617 if (!(already || hush || qopt))
618 printf("No new messages.\n");
619 exit(0);
620 }
621
622 void
623 prmesg(length)
624 int length;
625 {
626 FILE *outf;
627 char *env_pager;
628
629 if (use_pager && length > Lpp) {
630 signal(SIGPIPE, SIG_IGN);
631 signal(SIGQUIT, SIG_IGN);
632 if ((env_pager = getenv("PAGER")) == NULL) {
633 sprintf(cmdbuf, _PATH_PAGER, Lpp);
634 } else {
635 strcpy(cmdbuf, env_pager);
636 }
637 outf = popen(cmdbuf, "w");
638 if (!outf)
639 outf = stdout;
640 else
641 setbuf(outf, (char *)NULL);
642 }
643 else
644 outf = stdout;
645
646 if (seensubj)
647 putc('\n', outf);
648
649 while (fgets(inbuf, sizeof inbuf, newmsg)) {
650 fputs(inbuf, outf);
651 if (ferror(outf)) {
652 clearerr(outf);
653 break;
654 }
655 }
656
657 if (outf != stdout) {
658 pclose(outf);
659 signal(SIGPIPE, SIG_DFL);
660 signal(SIGQUIT, SIG_DFL);
661 }
662 else {
663 fflush(stdout);
664 }
665
666 /* trick to force wait on output */
667 tcdrain(fileno(stdout));
668 }
669
670 void
671 onintr(dummy)
672 int dummy;
673 {
674 signal(SIGINT, onintr);
675 if (mailing)
676 unlink(fname);
677 if (sending) {
678 unlink(fname);
679 puts("--Killed--");
680 exit(1);
681 }
682 if (printing) {
683 putchar('\n');
684 if (hdrs)
685 exit(0);
686 sep = "Interrupt";
687 if (newmsg)
688 fseek(newmsg, 0L, 2);
689 intrpflg = YES;
690 }
691 }
692
693 /*
694 * We have just gotten a susp. Suspend and prepare to resume.
695 */
696 void
697 onsusp(dummy)
698 int dummy;
699 {
700
701 signal(SIGTSTP, SIG_DFL);
702 sigsetmask(0);
703 kill(0, SIGTSTP);
704 signal(SIGTSTP, onsusp);
705 if (!mailing)
706 longjmp(tstpbuf, 0);
707 }
708
709 int
710 linecnt(f)
711 FILE *f;
712 {
713 off_t oldpos = ftell(f);
714 int l = 0;
715 char lbuf[BUFSIZ];
716
717 while (fgets(lbuf, sizeof lbuf, f))
718 l++;
719 clearerr(f);
720 fseek(f, oldpos, 0);
721 return (l);
722 }
723
724 int
725 next(buf)
726 char *buf;
727 {
728 int i;
729 sscanf(buf, "%d", &i);
730 sprintf(buf, "Goto %d", i);
731 return(--i);
732 }
733
734 void
735 ask(prompt)
736 char *prompt;
737 {
738 char inch;
739 int n, cmsg;
740 off_t oldpos;
741 FILE *cpfrom, *cpto;
742
743 printf("%s ", prompt);
744 fflush(stdout);
745 intrpflg = NO;
746 (void) fgets(inbuf, sizeof inbuf, stdin);
747 if ((n = strlen(inbuf)) > 0 && inbuf[n - 1] == '\n')
748 inbuf[n - 1] = '\0';
749 if (intrpflg)
750 inbuf[0] = 'x';
751
752 /*
753 * Handle 'mail' and 'save' here.
754 */
755 if (((inch = inbuf[0]) == 's' || inch == 'm') && !restricted) {
756 if (inbuf[1] == '-')
757 cmsg = prevmsg;
758 else if (isdigit(inbuf[1]))
759 cmsg = atoi(&inbuf[1]);
760 else
761 cmsg = msg;
762 sprintf(fname, "%s/%d", _PATH_MSGS, cmsg);
763
764 oldpos = ftell(newmsg);
765
766 cpfrom = fopen(fname, "r");
767 if (!cpfrom) {
768 printf("Message %d not found\n", cmsg);
769 ask (prompt);
770 return;
771 }
772
773 if (inch == 's') {
774 in = nxtfld(inbuf);
775 if (*in) {
776 for (n=0; in[n] > ' '; n++) { /* sizeof fname? */
777 fname[n] = in[n];
778 }
779 fname[n] = '\0';
780 }
781 else
782 strcpy(fname, "Messages");
783 }
784 else {
785 strcpy(fname, _PATH_TMP);
786 mktemp(fname);
787 sprintf(cmdbuf, _PATH_MAIL, fname);
788 mailing = YES;
789 }
790 cpto = fopen(fname, "a");
791 if (!cpto) {
792 perror(fname);
793 mailing = NO;
794 fseek(newmsg, oldpos, 0);
795 ask(prompt);
796 return;
797 }
798
799 while ((n = fread(inbuf, 1, sizeof inbuf, cpfrom)) != 0)
800 fwrite(inbuf, 1, n, cpto);
801
802 fclose(cpfrom);
803 fclose(cpto);
804 fseek(newmsg, oldpos, 0); /* reposition current message */
805 if (inch == 's')
806 printf("Message %d saved in \"%s\"\n", cmsg, fname);
807 else {
808 system(cmdbuf);
809 unlink(fname);
810 mailing = NO;
811 }
812 ask(prompt);
813 }
814 }
815
816 void
817 gfrsub(infile)
818 FILE *infile;
819 {
820 off_t frompos;
821
822 seensubj = seenfrom = NO;
823 local = YES;
824 subj[0] = from[0] = date[0] = 0;
825
826 /*
827 * Is this a normal message?
828 */
829 if (fgets(inbuf, sizeof inbuf, infile)) {
830 if (strncmp(inbuf, "From", 4)==0) {
831 /*
832 * expected form starts with From
833 */
834 seenfrom = YES;
835 frompos = ftell(infile);
836 ptr = from;
837 in = nxtfld(inbuf);
838 if (*in) while (*in && *in > ' ') {
839 if (*in == ':' || *in == '@' || *in == '!')
840 local = NO;
841 *ptr++ = *in++;
842 /* what about sizeof from ? */
843 }
844 *ptr = '\0';
845 if (*(in = nxtfld(in)))
846 strncpy(date, in, sizeof date);
847 else {
848 date[0] = '\n';
849 date[1] = '\0';
850 }
851 }
852 else {
853 /*
854 * not the expected form
855 */
856 fseek(infile, 0L, 0);
857 return;
858 }
859 }
860 else
861 /*
862 * empty file ?
863 */
864 return;
865
866 /*
867 * look for Subject line until EOF or a blank line
868 */
869 while (fgets(inbuf, sizeof inbuf, infile)
870 && !(blankline = (inbuf[0] == '\n'))) {
871 /*
872 * extract Subject line
873 */
874 if (!seensubj && strncmp(inbuf, "Subj", 4)==0) {
875 seensubj = YES;
876 frompos = ftell(infile);
877 strncpy(subj, nxtfld(inbuf), sizeof subj);
878 }
879 }
880 if (!blankline)
881 /*
882 * ran into EOF
883 */
884 fseek(infile, frompos, 0);
885
886 if (!seensubj)
887 /*
888 * for possible use with Mail
889 */
890 strncpy(subj, "(No Subject)\n", sizeof subj);
891 }
892
893 char *
894 nxtfld(s)
895 char *s;
896 {
897 if (*s) while (*s && *s > ' ') s++; /* skip over this field */
898 if (*s) while (*s && *s <= ' ') s++; /* find start of next field */
899 return (s);
900 }
901