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