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