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