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