1 /* $NetBSD: msgs.c,v 1.8 1997/05/17 20:09:26 pk 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.8 1997/05/17 20:09:26 pk 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] = '\0'; 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] = 0; 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 = '\0'; 825 if (*(in = nxtfld(in))) 826 strncpy(date, in, sizeof date); 827 else { 828 date[0] = '\n'; 829 date[1] = '\0'; 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