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