|
|
1.1 ! root 1: /* ! 2: * msgs - a user bulletin board program ! 3: * ! 4: * usage: ! 5: * msgs [fhlopq] [[-]number] to read messages ! 6: * msgs -s to place messages ! 7: * msgs -c [-days] to clean up the bulletin board ! 8: * ! 9: * prompt commands are: ! 10: * y print message ! 11: * n flush message, go to next message ! 12: * q flush message, quit ! 13: * p print message, turn on 'pipe thru more' mode ! 14: * P print message, turn off 'pipe thru more' mode ! 15: * - reprint last message ! 16: * s[-][<num>] [<filename>] save message ! 17: * m[-][<num>] mail with message in temp mbox ! 18: * x exit without flushing this message ! 19: */ ! 20: ! 21: #define V7 /* will look for TERM in the environment */ ! 22: #define OBJECT /* will object to messages without Subjects */ ! 23: /* #define REJECT /* will reject messages without Subjects ! 24: (OBJECT must be defined also) */ ! 25: /* #define UNBUFFERED /* use unbuffered output */ ! 26: ! 27: #include <stdio.h> ! 28: #include <sys/types.h> ! 29: #include <signal.h> ! 30: #include <sys/dir.h> ! 31: #include <sys/stat.h> ! 32: #include <ctype.h> ! 33: #include <pwd.h> ! 34: #include <sgtty.h> ! 35: #include "msgs.h" ! 36: ! 37: #define CMODE 0666 /* bounds file creation mode */ ! 38: #define NO 0 ! 39: #define YES 1 ! 40: #define SUPERUSER 0 /* superuser uid */ ! 41: #define DAEMON 1 /* daemon uid */ ! 42: #define NLINES 24 /* default number of lines/crt screen */ ! 43: #define NDAYS 21 /* default keep time for messages */ ! 44: #define DAYS *24*60*60 /* seconds/day */ ! 45: #define TEMP "/tmp/msgXXXXXX" ! 46: #define MSGSRC ".msgsrc" /* user's rc file */ ! 47: #define BOUNDS "bounds" /* message bounds file */ ! 48: #define NEXT "Next message? [yq]" ! 49: #define MORE "More? [ynq]" ! 50: #define NOMORE "(No more) [q] ?" ! 51: ! 52: typedef char bool; ! 53: ! 54: FILE *newmsg; ! 55: char *sep = "-"; ! 56: char inbuf[BUFSIZ]; ! 57: char fname[128]; ! 58: char cmdbuf[128]; ! 59: char subj[128]; ! 60: char from[128]; ! 61: char date[128]; ! 62: char *ptr; ! 63: char *in; ! 64: bool local; ! 65: bool ruptible; ! 66: bool totty; ! 67: bool seenfrom; ! 68: bool seensubj; ! 69: bool blankline; ! 70: bool printing = NO; ! 71: bool mailing = NO; ! 72: bool quitit = NO; ! 73: bool sending = NO; ! 74: bool intrpflg = NO; ! 75: int uid; ! 76: int msg; ! 77: int prevmsg; ! 78: int lct; ! 79: int nlines; ! 80: int Lpp = NLINES; ! 81: time_t t; ! 82: time_t keep; ! 83: struct sgttyb otty; ! 84: ! 85: char *ctime(); ! 86: char *nxtfld(); ! 87: int onintr(); ! 88: off_t ftell(); ! 89: FILE *popen(); ! 90: struct passwd *getpwuid(); ! 91: ! 92: extern int errno; ! 93: ! 94: /* option initialization */ ! 95: bool hdrs = NO; ! 96: bool qopt = NO; ! 97: bool hush = NO; ! 98: bool send = NO; ! 99: bool locomode = NO; ! 100: bool pause = NO; ! 101: bool clean = NO; ! 102: bool lastcmd = NO; ! 103: ! 104: main(argc, argv) ! 105: int argc; char *argv[]; ! 106: { ! 107: bool newrc, already; ! 108: int rcfirst = 0; /* first message to print (from .rc) */ ! 109: int rcback = 0; /* amount to back off of rcfirst*/ ! 110: int firstmsg, nextmsg, lastmsg = 0; ! 111: int blast = 0; ! 112: FILE *bounds, *msgsrc; ! 113: ! 114: #ifndef UNBUFFERED ! 115: char obuf[BUFSIZ]; ! 116: setbuf(stdout, obuf); ! 117: #else ! 118: setbuf(stdout, NULL); ! 119: #endif ! 120: ! 121: gtty(fileno(stdout), &otty); ! 122: time(&t); ! 123: setuid(uid = getuid()); ! 124: ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL); ! 125: if (ruptible) ! 126: signal(SIGINT, SIG_DFL); ! 127: ! 128: argc--, argv++; ! 129: while (argc > 0) { ! 130: if (isdigit(argv[0][0])) { /* starting message # */ ! 131: rcfirst = atoi(argv[0]); ! 132: } ! 133: else if (isdigit(argv[0][1])) { /* backward offset */ ! 134: rcback = atoi( &( argv[0][1] ) ); ! 135: } ! 136: else { ! 137: ptr = *argv; ! 138: while (*ptr) switch (*ptr++) { ! 139: ! 140: case '-': ! 141: break; ! 142: ! 143: case 'c': ! 144: if (uid != SUPERUSER && uid != DAEMON) { ! 145: fprintf(stderr, "Sorry\n"); ! 146: exit(1); ! 147: } ! 148: clean = YES; ! 149: break; ! 150: ! 151: case 'f': /* silently */ ! 152: hush = YES; ! 153: break; ! 154: ! 155: case 'h': /* headers only */ ! 156: hdrs = YES; ! 157: break; ! 158: ! 159: case 'l': /* local msgs only */ ! 160: locomode = YES; ! 161: break; ! 162: ! 163: case 'o': /* option to save last message */ ! 164: lastcmd = YES; ! 165: break; ! 166: ! 167: case 'p': /* pipe thru 'more' during long msgs */ ! 168: pause = YES; ! 169: break; ! 170: ! 171: case 'q': /* query only */ ! 172: qopt = YES; ! 173: break; ! 174: ! 175: case 's': /* sending TO msgs */ ! 176: send = YES; ! 177: break; ! 178: ! 179: default: ! 180: fprintf(stderr, ! 181: "usage: msgs [fhlopq] [[-]number]\n"); ! 182: exit(1); ! 183: } ! 184: } ! 185: argc--, argv++; ! 186: } ! 187: ! 188: /* ! 189: * determine current message bounds ! 190: */ ! 191: sprintf(fname, "%s/%s", USRMSGS, BOUNDS); ! 192: bounds = fopen(fname, "r"); ! 193: ! 194: if (bounds != NULL) { ! 195: fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg); ! 196: fclose(bounds); ! 197: blast = lastmsg; /* save upper bound */ ! 198: } ! 199: ! 200: if (clean) ! 201: keep = t - (rcback? rcback : NDAYS) DAYS; ! 202: ! 203: if (clean || bounds == NULL) { /* relocate message bounds */ ! 204: struct direct dirent; ! 205: struct stat stbuf; ! 206: bool seenany = NO; ! 207: ! 208: FILE *d = fopen(USRMSGS, "r"); ! 209: if (d == NULL) { ! 210: perror(USRMSGS); ! 211: exit(errno); ! 212: } ! 213: ! 214: firstmsg = 32767; ! 215: lastmsg = 0; ! 216: ! 217: while (fread(&dirent, sizeof dirent, 1, d) == 1) { ! 218: register char *cp = dirent.d_name; ! 219: register int i = 0; ! 220: ! 221: if (dirent.d_ino == 0) ! 222: continue; ! 223: ! 224: if (clean) ! 225: sprintf(inbuf, "%s/%s", USRMSGS, cp); ! 226: ! 227: while (isdigit(*cp)) ! 228: i = i * 10 + *cp++ - '0'; ! 229: if (*cp) ! 230: continue; /* not a message! */ ! 231: ! 232: if (clean) { ! 233: if (stat(inbuf, &stbuf) != 0) ! 234: continue; ! 235: if (stbuf.st_mtime < keep ! 236: && stbuf.st_mode&S_IWRITE) { ! 237: unlink(inbuf); ! 238: continue; ! 239: } ! 240: } ! 241: ! 242: if (i > lastmsg) ! 243: lastmsg = i; ! 244: if (i < firstmsg) ! 245: firstmsg = i; ! 246: seenany = YES; ! 247: } ! 248: fclose(d); ! 249: ! 250: if (!seenany) { ! 251: if (blast != 0) /* never lower the upper bound! */ ! 252: lastmsg = blast; ! 253: firstmsg = lastmsg + 1; ! 254: } ! 255: else if (blast > lastmsg) ! 256: lastmsg = blast; ! 257: ! 258: if (!send) { ! 259: bounds = fopen(fname, "w"); ! 260: if (bounds == NULL) { ! 261: perror(fname); ! 262: exit(errno); ! 263: } ! 264: chmod(fname, CMODE); ! 265: fprintf(bounds, "%d %d\n", firstmsg, lastmsg); ! 266: fclose(bounds); ! 267: } ! 268: } ! 269: ! 270: if (send) { ! 271: /* ! 272: * Send mode - place msgs in USRMSGS ! 273: */ ! 274: bounds = fopen(fname, "w"); ! 275: if (bounds == NULL) { ! 276: perror(fname); ! 277: exit(errno); ! 278: } ! 279: ! 280: nextmsg = lastmsg + 1; ! 281: sprintf(fname, "%s/%d", USRMSGS, nextmsg); ! 282: newmsg = fopen(fname, "w"); ! 283: if (newmsg == NULL) { ! 284: perror(fname); ! 285: exit(errno); ! 286: } ! 287: chmod(fname, 0644); ! 288: ! 289: fprintf(bounds, "%d %d\n", firstmsg, nextmsg); ! 290: fclose(bounds); ! 291: ! 292: sending = YES; ! 293: if (ruptible) ! 294: signal(SIGINT, onintr); ! 295: ! 296: if (isatty(fileno(stdin))) { ! 297: ptr = getpwuid(uid)->pw_name; ! 298: printf("Message %d:\nFrom %s %sSubject: ", ! 299: nextmsg, ptr, ctime(&t)); ! 300: fflush(stdout); ! 301: fgets(inbuf, sizeof inbuf, stdin); ! 302: putchar('\n'); ! 303: fflush(stdout); ! 304: fprintf(newmsg, "From %s %sSubject: %s\n", ! 305: ptr, ctime(&t), inbuf); ! 306: blankline = seensubj = YES; ! 307: } ! 308: else ! 309: blankline = seensubj = NO; ! 310: for (;;) { ! 311: fgets(inbuf, sizeof inbuf, stdin); ! 312: if (feof(stdin) || ferror(stdin)) ! 313: break; ! 314: blankline = (blankline || (inbuf[0] == '\n')); ! 315: seensubj = (seensubj || (!blankline && (strncmp(inbuf, "Subj", 4) == 0))); ! 316: fputs(inbuf, newmsg); ! 317: } ! 318: #ifdef OBJECT ! 319: if (!seensubj) { ! 320: printf("NOTICE: Messages should have a Subject field!\n"); ! 321: #ifdef REJECT ! 322: unlink(fname); ! 323: #endif ! 324: exit(1); ! 325: } ! 326: #endif ! 327: exit(ferror(stdin)); ! 328: } ! 329: if (clean) ! 330: exit(0); ! 331: ! 332: /* ! 333: * prepare to display messages ! 334: */ ! 335: totty = (isatty(fileno(stdout)) != 0); ! 336: pause = pause && totty; ! 337: ! 338: sprintf(fname, "%s/%s", getenv("HOME"), MSGSRC); ! 339: msgsrc = fopen(fname, "r"); ! 340: if (msgsrc) { ! 341: newrc = NO; ! 342: fscanf(msgsrc, "%d\n", &nextmsg); ! 343: fclose(msgsrc); ! 344: if (!rcfirst) ! 345: rcfirst = nextmsg - rcback; ! 346: } ! 347: else { ! 348: newrc = YES; ! 349: nextmsg = 0; ! 350: } ! 351: msgsrc = fopen(fname, "a"); ! 352: if (msgsrc == NULL) { ! 353: perror(fname); ! 354: exit(errno); ! 355: } ! 356: if (rcfirst) ! 357: firstmsg = rcfirst; ! 358: if (newrc) { ! 359: nextmsg = firstmsg; ! 360: fseek(msgsrc, 0L, 0); ! 361: fprintf(msgsrc, "%d\n", nextmsg); ! 362: fflush(msgsrc); ! 363: } ! 364: ! 365: #ifdef V7 ! 366: if (totty) { ! 367: if (tgetent(inbuf, getenv("TERM")) <= 0 ! 368: || (Lpp = tgetnum("li")) <= 0) { ! 369: Lpp = NLINES; ! 370: } ! 371: } ! 372: #endif ! 373: Lpp -= 6; /* for headers, etc. */ ! 374: ! 375: already = NO; ! 376: prevmsg = firstmsg; ! 377: printing = YES; ! 378: if (ruptible) ! 379: signal(SIGINT, onintr); ! 380: ! 381: /* ! 382: * Main program loop ! 383: */ ! 384: for (msg = firstmsg; msg <= lastmsg; msg++) { ! 385: ! 386: sprintf(fname, "%s/%d", USRMSGS, msg); ! 387: newmsg = fopen(fname, "r"); ! 388: if (newmsg == NULL) ! 389: continue; ! 390: ! 391: gfrsub(newmsg); /* get From and Subject fields */ ! 392: if (locomode && !local) { ! 393: fclose(newmsg); ! 394: continue; ! 395: } ! 396: ! 397: if (qopt) { /* This has to be located here */ ! 398: printf("There are new messages.\n"); ! 399: exit(0); ! 400: } ! 401: ! 402: if (already && !hdrs) ! 403: putchar('\n'); ! 404: already = YES; ! 405: ! 406: /* ! 407: * Print header ! 408: */ ! 409: nlines = 2; ! 410: if (seenfrom) { ! 411: printf("Message %d:\nFrom %s %s", msg, from, date); ! 412: nlines++; ! 413: } ! 414: if (seensubj) { ! 415: printf("Subject: %s", subj); ! 416: nlines++; ! 417: } ! 418: else { ! 419: if (seenfrom) { ! 420: putchar('\n'); ! 421: nlines++; ! 422: } ! 423: while (nlines < 6 ! 424: && fgets(inbuf, sizeof inbuf, newmsg) ! 425: && inbuf[0] != '\n') { ! 426: fputs(inbuf, stdout); ! 427: nlines++; ! 428: } ! 429: } ! 430: ! 431: lct = linecnt(newmsg); ! 432: if (lct) ! 433: printf("(%d%slines) ", lct, seensubj? " " : " more "); ! 434: ! 435: if (hdrs) { ! 436: printf("\n-----\n"); ! 437: fclose(newmsg); ! 438: continue; ! 439: } ! 440: ! 441: /* ! 442: * Ask user for command ! 443: */ ! 444: if (totty) ! 445: ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT)); ! 446: else ! 447: inbuf[0] = 'y'; ! 448: cmnd: ! 449: in = inbuf; ! 450: switch (*in) { ! 451: case 'x': ! 452: case 'X': ! 453: exit(0); ! 454: ! 455: case 'q': ! 456: case 'Q': ! 457: quitit = YES; ! 458: printf("--Postponed--\n"); ! 459: exit(0); ! 460: /* intentional fall-thru */ ! 461: case 'n': ! 462: case 'N': ! 463: if (msg >= nextmsg) sep = "Flushed"; ! 464: break; ! 465: ! 466: case 'p': ! 467: case 'P': ! 468: pause = (*in++ == 'p'); ! 469: /* intentional fallthru */ ! 470: case '\n': ! 471: case 'y': ! 472: default: ! 473: if (*in == '-') { ! 474: msg = prevmsg-1; ! 475: sep = "replay"; ! 476: break; ! 477: } ! 478: if (isdigit(*in)) { ! 479: msg = next(in); ! 480: sep = in; ! 481: break; ! 482: } ! 483: ! 484: prmesg(nlines + lct + (seensubj? 1 : 0)); ! 485: prevmsg = msg; ! 486: ! 487: } ! 488: ! 489: printf("--%s--\n", sep); ! 490: sep = "-"; ! 491: if (msg >= nextmsg) { ! 492: nextmsg = msg + 1; ! 493: fseek(msgsrc, 0L, 0); ! 494: fprintf(msgsrc, "%d\n", nextmsg); ! 495: fflush(msgsrc); ! 496: } ! 497: if (newmsg) ! 498: fclose(newmsg); ! 499: if (quitit) ! 500: break; ! 501: } ! 502: ! 503: if (already && !quitit && lastcmd && totty) { ! 504: /* ! 505: * save or reply to last message? ! 506: */ ! 507: msg = prevmsg; ! 508: ask(NOMORE); ! 509: if (inbuf[0] == '-' || isdigit(inbuf[0])) ! 510: goto cmnd; ! 511: } ! 512: if (!(already || hush || qopt)) ! 513: printf("No new messages.\n"); ! 514: exit(0); ! 515: } ! 516: ! 517: prmesg(length) ! 518: int length; ! 519: { ! 520: FILE *outf, *inf; ! 521: int c; ! 522: ! 523: if (pause && length > Lpp) { ! 524: sprintf(cmdbuf, PAGE, Lpp); ! 525: outf = popen(cmdbuf, "w"); ! 526: if (!outf) ! 527: outf = stdout; ! 528: else ! 529: setbuf(outf, NULL); ! 530: } ! 531: else ! 532: outf = stdout; ! 533: ! 534: if (seensubj) ! 535: putc('\n', outf); ! 536: ! 537: while (fgets(inbuf, sizeof inbuf, newmsg)) ! 538: fputs(inbuf, outf); ! 539: ! 540: if (outf != stdout) { ! 541: pclose(outf); ! 542: } ! 543: else { ! 544: fflush(stdout); ! 545: } ! 546: ! 547: /* trick to force wait on output */ ! 548: stty(fileno(stdout), &otty); ! 549: } ! 550: ! 551: onintr() ! 552: { ! 553: signal(SIGINT, onintr); ! 554: if (mailing) ! 555: unlink(fname); ! 556: if (sending) { ! 557: unlink(fname); ! 558: puts("--Killed--"); ! 559: exit(1); ! 560: } ! 561: if (printing) { ! 562: putchar('\n'); ! 563: if (hdrs) ! 564: exit(0); ! 565: sep = "Interrupt"; ! 566: if (newmsg) ! 567: fseek(newmsg, 0L, 2); ! 568: intrpflg = YES; ! 569: } ! 570: } ! 571: ! 572: linecnt(f) ! 573: FILE *f; ! 574: { ! 575: off_t oldpos = ftell(f); ! 576: int l = 0; ! 577: char lbuf[BUFSIZ]; ! 578: ! 579: while (fgets(lbuf, sizeof lbuf, f)) ! 580: l++; ! 581: clearerr(f); ! 582: fseek(f, oldpos, 0); ! 583: return (l); ! 584: } ! 585: ! 586: next(buf) ! 587: char *buf; ! 588: { ! 589: int i; ! 590: sscanf(buf, "%d", &i); ! 591: sprintf(buf, "Goto %d", i); ! 592: return(--i); ! 593: } ! 594: ! 595: ask(prompt) ! 596: char *prompt; ! 597: { ! 598: char inch; ! 599: int n, cmsg; ! 600: off_t oldpos; ! 601: FILE *cpfrom, *cpto; ! 602: ! 603: printf("%s ", prompt); ! 604: fflush(stdout); ! 605: intrpflg = NO; ! 606: gets(inbuf); ! 607: if (intrpflg) ! 608: inbuf[0] = 'x'; ! 609: ! 610: /* ! 611: * Handle 'mail' and 'save' here. ! 612: */ ! 613: if ((inch = inbuf[0]) == 's' || inch == 'm') { ! 614: if (inbuf[1] == '-') ! 615: cmsg = prevmsg; ! 616: else if (isdigit(inbuf[1])) ! 617: cmsg = atoi(&inbuf[1]); ! 618: else ! 619: cmsg = msg; ! 620: sprintf(fname, "%s/%d", USRMSGS, cmsg); ! 621: ! 622: oldpos = ftell(newmsg); ! 623: ! 624: cpfrom = fopen(fname, "r"); ! 625: if (!cpfrom) { ! 626: printf("Message %d not found\n", cmsg); ! 627: ask (prompt); ! 628: return; ! 629: } ! 630: ! 631: if (inch == 's') { ! 632: in = nxtfld(inbuf); ! 633: if (*in) { ! 634: for (n=0; in[n] > ' '; n++) { /* sizeof fname? */ ! 635: fname[n] = in[n]; ! 636: } ! 637: fname[n] = NULL; ! 638: } ! 639: else ! 640: strcpy(fname, "Messages"); ! 641: } ! 642: else { ! 643: strcpy(fname, TEMP); ! 644: mktemp(fname); ! 645: sprintf(cmdbuf, MAIL, fname); ! 646: mailing = YES; ! 647: } ! 648: cpto = fopen(fname, "a"); ! 649: if (!cpto) { ! 650: perror(fname); ! 651: mailing = NO; ! 652: fseek(newmsg, oldpos, 0); ! 653: ask(prompt); ! 654: return; ! 655: } ! 656: ! 657: while (n = fread(inbuf, 1, sizeof inbuf, cpfrom)) ! 658: fwrite(inbuf, 1, n, cpto); ! 659: ! 660: fclose(cpfrom); ! 661: fclose(cpto); ! 662: fseek(newmsg, oldpos, 0); /* reposition current message */ ! 663: if (inch == 's') ! 664: printf("Message %d saved in \"%s\"\n", cmsg, fname); ! 665: else { ! 666: system(cmdbuf); ! 667: unlink(fname); ! 668: mailing = NO; ! 669: } ! 670: ask(prompt); ! 671: } ! 672: } ! 673: ! 674: gfrsub(infile) ! 675: FILE *infile; ! 676: { ! 677: off_t frompos; ! 678: ! 679: seensubj = seenfrom = NO; ! 680: local = YES; ! 681: subj[0] = from[0] = date[0] = NULL; ! 682: ! 683: /* ! 684: * Is this a normal message? ! 685: */ ! 686: if (fgets(inbuf, sizeof inbuf, infile)) { ! 687: if (strncmp(inbuf, "From", 4)==0) { ! 688: /* ! 689: * expected form starts with From ! 690: */ ! 691: seenfrom = YES; ! 692: frompos = ftell(infile); ! 693: ptr = from; ! 694: in = nxtfld(inbuf); ! 695: if (*in) while (*in && *in > ' ') { ! 696: if (*in == ':') ! 697: local = NO; ! 698: *ptr++ = *in++; ! 699: /* what about sizeof from ? */ ! 700: } ! 701: *ptr = NULL; ! 702: if (*(in = nxtfld(in))) ! 703: strncpy(date, in, sizeof date); ! 704: else { ! 705: date[0] = '\n'; ! 706: date[1] = NULL; ! 707: } ! 708: } ! 709: else { ! 710: /* ! 711: * not the expected form ! 712: */ ! 713: fseek(infile, 0L, 0); ! 714: return; ! 715: } ! 716: } ! 717: else ! 718: /* ! 719: * empty file ? ! 720: */ ! 721: return; ! 722: ! 723: /* ! 724: * look for Subject line until EOF or a blank line ! 725: */ ! 726: while (fgets(inbuf, sizeof inbuf, infile) ! 727: && !(blankline = (inbuf[0] == '\n'))) { ! 728: /* ! 729: * extract Subject line ! 730: */ ! 731: if (!seensubj && strncmp(inbuf, "Subj", 4)==0) { ! 732: seensubj = YES; ! 733: frompos = ftell(infile); ! 734: strncpy(subj, nxtfld(inbuf), sizeof subj); ! 735: } ! 736: } ! 737: if (!blankline) ! 738: /* ! 739: * ran into EOF ! 740: */ ! 741: fseek(infile, frompos, 0); ! 742: ! 743: if (!seensubj) ! 744: /* ! 745: * for possible use with Mail ! 746: */ ! 747: strncpy(subj, "(No Subject)\n", sizeof subj); ! 748: } ! 749: ! 750: char * ! 751: nxtfld(s) ! 752: char *s; ! 753: { ! 754: if (*s) while (*s && *s > ' ') s++; /* skip over this field */ ! 755: if (*s) while (*s && *s <= ' ') s++; /* find start of next field */ ! 756: return (s); ! 757: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.