1: /* 2: * This software is Copyright (c) 1986 by Rick Adams. 3: * 4: * Permission is hereby granted to copy, reproduce, redistribute or 5: * otherwise use this software as long as: there is no monetary 6: * profit gained specifically from the use or reproduction or this 7: * software, it is not sold, rented, traded or otherwise marketed, and 8: * this copyright notice is included prominently in any copy 9: * made. 10: * 11: * The author make no claims as to the fitness or correctness of 12: * this software for any use whatsoever, and it is provided as is. 13: * Any use of this software is at the user's own risk. 14: * 15: * Postnews: post a news message to Usenet. This C version replaces a shell 16: * script, and does more intelligent prompting and filtering than possible 17: * in a shell script. 18: */ 19: 20: #ifdef SCCSID 21: static char *SccsId = "@(#)postnews.c 1.25 3/19/86"; 22: #endif /* SCCSID */ 23: 24: #include "params.h" 25: 26: #define APPEND 1 27: #define REPLACE 2 28: 29: extern char *MAILPARSER; 30: 31: char tempfname[50]; /* file name used for making article */ 32: char original[BUFLEN]; /* file name of original, used in followup */ 33: char homedir[BUFLEN]; /* HOME environment setting */ 34: char user[SBUFLEN]; /* user name */ 35: char ccname[BUFLEN]; /* file name for article copy */ 36: 37: /* article header information */ 38: char subject[BUFLEN]; 39: char distribution[BUFLEN]; 40: char references[BUFLEN]; 41: char newsgroups[BUFLEN]; 42: char moderator[BUFLEN]; 43: char isfrom[BUFLEN]; 44: char msgid[BUFLEN]; 45: char keywords[BUFLEN]; 46: char summary[BUFLEN]; 47: int uid; 48: 49: char ngsep[] = { NGDELIM, '\0' }; /* == "," */ 50: 51: char *Progname = "postnews"; /* for xerror */ 52: 53: time_t fmodtime; 54: int ismod = 0; 55: char buf[BUFLEN]; 56: 57: struct distr { 58: char abbr[24]; 59: char descr[128]; 60: } distr[16]; 61: 62: FILE *xfopen(); 63: 64: main(argc, argv) 65: char *argv[]; 66: { 67: register int c; 68: 69: init(); 70: 71: if (argc == 2) { 72: if (!prefix(argv[1], SPOOL)) 73: xerror("Can only followup to articles in %s", SPOOL); 74: followup(argv[1]); 75: (void) strcpy(original, argv[1]); 76: } else 77: if (askyes("Is this message in response to some other message? ","no")) { 78: char ng[BUFLEN], num[BUFLEN]; 79: long i, j, lastnum; 80: register char *p; 81: int fd, dir; 82: char canpost; 83: 84: getpr("In what newsgroup was the article posted? ",ng); 85: if (!valid_ng(ng, &i, &j, &canpost)) 86: if (canpost != 'n' ) 87: byebye("There is no such newsgroup."); 88: else 89: byebye("You are not allowed to post to that group."); 90: 91: printf("Valid article numbers are from %ld to %ld\n", j, i); 92: lastnum = i + 1; 93: dir = -1; 94: 95: for(;;) { 96: getpr("\nWhat was the article number? ", num); 97: switch(num[0]) { 98: case '+': 99: dir = 1; 100: sprintf(num, "%ld", lastnum + 1); 101: break; 102: case '-': 103: dir = -1; 104: /* no break */ 105: case '\0': 106: sprintf(num, "%ld", lastnum + dir); 107: break; 108: } 109: (void) sprintf(original, "%s/%s", SPOOL, ng); 110: for (p=original+strlen(SPOOL)+1; *p ;++p) 111: if (*p == '.') 112: *p = '/'; 113: (void) strcat(original, "/"); 114: (void) strcat(original, num); 115: 116: if ((fd=open(original,0)) >= 0) { 117: (void) close(fd); 118: printf("\narticle %s\n", original); 119: if (article_line(original, "From: ", buf)) 120: printf("%s\n", buf); 121: if (article_line(original, "Subject: ", buf)) 122: printf("%s\n", buf); 123: if (askyes("Is this the one you want? ", "n")) 124: break; 125: } else 126: printf("I can't find that article.\n"); 127: lastnum = atol(num); 128: } 129: 130: followup(original); 131: } else { 132: do { 133: getpr("Subject: ", subject); 134: if (*subject == '?') { 135: printf("People read the subject line to learn what your article is about.\n"); 136: printf("You want it to do the same job as a newspaper headline.\n"); 137: printf("So type in something both brief and descriptive.\n"); 138: *subject = '\0'; 139: } 140: } while (*subject == '\0'); 141: getpr("Keywords: ", keywords); 142: 143: while (!get_newsgroup()) 144: ; 145: check_mod(); 146: get_distribution((char *)0); 147: } 148: 149: if (pre_checks()) 150: exit(1); 151: 152: prep_article(); 153: c = 'e'; 154: for (;;) { 155: if (c == 'e') { 156: edit_article(); 157: post_checks(); 158: } 159: do { 160: do { 161: getpr("\nWhat now? [send, edit, list, quit, write] ", buf); 162: c = buf[0]; 163: } while (c == '\0'); 164: if (isupper(c)) 165: c = tolower(c); 166: if (c == 'q') { 167: (void) UNLINK(tempfname); 168: exit(1); 169: } 170: if (c == 'l') { 171: char *pager = getenv("PAGER"); 172: char lbuf[BUFLEN]; 173: if (pager == NULL || *pager == '\0') { 174: #ifdef PAGE 175: # ifdef IHCC 176: (void) sprintf(lbuf,"%s/bin/%s", logdir(HOME), PAGE); 177: # else /* !IHCC */ 178: (void) strcpy(lbuf, PAGE); 179: # endif /* !IHCC */ 180: pager = lbuf; 181: #else /* !PAGE */ 182: pager = "cat"; 183: #endif /* !PAGE */ 184: } 185: sprintf(buf, "exec %s %s", pager, tempfname); 186: (void) system(buf); 187: } 188: if (c == 'w') { 189: register int ifd, ofd, nbytes; 190: char iobuf[BUFSIZ]; 191: char fname[BUFLEN]; 192: getpr("Filename? ", fname); 193: if (fname[0] == '\0') 194: continue; 195: ofd = creat(fname, 0666); 196: if (ofd < 0) 197: perror(fname); 198: else { 199: ifd = open(tempfname, 0); 200: if (ifd < 0) 201: xerror("Can't reopen %s\n", tempfname); 202: while ((nbytes = read(ifd, iobuf, BUFSIZ)) > 0 ) 203: write(ofd, iobuf, nbytes); 204: close(ofd); 205: close(ifd); 206: } 207: } 208: } while (!index("eps", c)); 209: if (c != 'e') 210: post_article(); /* will exit if posted successfully */ 211: }; 212: } 213: 214: /* 215: * Find out the topic of interest. 216: */ 217: get_newsgroup() 218: { 219: int n; 220: long i; 221: char canpost; 222: static int first = 1; 223: 224: printf("Newsgroups (enter one at a time, end with a blank line):\n"); 225: if (first) { 226: printf("\nThe most relevant newsgroup should be the first, you should\n"); 227: printf("add others only if your article really MUST be read by people\n"); 228: printf("who choose not to read the appropriate group for your article.\n"); 229: printf("But DO use multiple newsgroups rather than posting many times.\n\n"); 230: first = 0; 231: } 232: printf("For a list of newsgroups, type ?\n"); 233: n = 0; 234: newsgroups[0] = '\0'; 235: 236: for(;;) { 237: getpr("> ", buf); 238: if (buf[0] == '\0') 239: if (n == 0) 240: return FALSE; 241: else 242: return TRUE; 243: if (buf[0] == '?'){ 244: char *pager = getenv("PAGER"); 245: char lbuf[BUFLEN]; 246: if (pager == NULL) { 247: #ifdef PAGE 248: # ifdef IHCC 249: (void) sprintf(lbuf,"%s/bin/%s", logdir(HOME), PAGE); 250: # else /* !IHCC */ 251: (void) strcpy(lbuf, PAGE); 252: # endif /* !IHCC */ 253: pager = lbuf; 254: #else /* !PAGE */ 255: pager = "cat"; 256: #endif /* !PAGE */ 257: } 258: printf("These are the currently active groups:\n"); 259: sprintf(buf, "exec %s %s/newsgroups", pager, LIB); 260: (void) system(buf); 261: continue; 262: } 263: if (valid_ng(buf, &i, &i, &canpost)) { 264: if (n++ != 0) 265: (void) strcat(newsgroups, ngsep); 266: (void) strcat(newsgroups, buf); 267: } else { 268: if (canpost == 'n') 269: printf("You are not allowed to post to %s\n", 270: buf); 271: else 272: printf("%s is not a valid newsgroup.\n", buf); 273: } 274: } 275: } 276: 277: /* 278: * Find out how widely the author wants the message distributed. 279: */ 280: get_distribution(deflt) 281: char *deflt; 282: { 283: register int i; 284: register char *r; 285: char def[BUFLEN]; 286: char *lastgroup; 287: 288: lastgroup = newsgroups; 289: (void) strcpy(def, newsgroups); 290: r = index(def, NGDELIM); 291: if (r) 292: *r = '\0'; 293: r = index(def, '.'); 294: if (r) { 295: *r = '\0'; 296: if (strcmp(def, "net") == 0) 297: (void) strcpy(def, "world"); 298: } else { 299: distribution[0] = '\0'; 300: return; 301: } 302: 303: if (strcmp(def, "to") == 0) { 304: /* 305: * This only works if "to.xx" is the first (or only) 306: * newsgroup, but it usually is .. 307: * Perhaps we should make the distribution be "to.xxx" ?? 308: */ 309: distribution[0] = '\0'; 310: return; /* He's probably testing something */ 311: } 312: if (deflt != (char *)0) 313: (void) strcpy(def, deflt); 314: if (ngmatch("net.test", newsgroups)) 315: (void) strcpy(def, "local"); 316: for(;;) { 317: do { 318: (void) sprintf(buf, "Distribution (default='%s', '?' for help) : ", def); 319: getpr(buf, distribution); 320: if (distribution[0] == '\0') { 321: if (strcmp(def, "*None*") == 0) 322: printf("You must enter a distribution, '?' for help.\n"); 323: (void) strcpy(distribution, def); 324: } 325: } while (strcmp(distribution, "*None*") == 0); 326: 327: /* Did the user ask for help? */ 328: if (distribution[0] == '?') { 329: printf("How widely should your article be distributed?\n\n"); 330: for (i=0; distr[i].abbr[0]; i++) 331: printf("%s\t%s\n", distr[i].abbr, distr[i].descr); 332: printf("\nEnter the word that specifies the distribution that you require.\n"); 333: continue; 334: } 335: 336: /* Check that it's a proper distribution */ 337: for (i=0; distr[i].abbr[0]; i++) { 338: if (strncmp(distr[i].abbr, distribution, sizeof(distr[0].abbr)) == 0) { 339: register int n; 340: /* Found a match. Do any special rewriting. */ 341: if (strcmp(distribution, "world") == 0) 342: strcpy(distribution, "net"); 343: r = newsgroups; 344: n = strlen(distribution); 345: /* 346: * A distribution of foo is useless 347: * if all the newsgroups are in foo.all 348: */ 349: for (;;) { 350: if (strncmp(r, distribution, n)) 351: return; 352: if ((r = index(r, NGDELIM)) == NULL) 353: break; 354: ++r; 355: } 356: distribution[0] = '\0'; 357: return; 358: } 359: } 360: if (strcmp(distribution, def) != 0) 361: printf("Type ? for help.\n"); 362: else { 363: int once = TRUE; 364: 365: do { 366: r = lastgroup; 367: while (r = index(r, NGDELIM)) 368: if (!prefix(++r, def)) 369: break; 370: if (r == NULL) { 371: /* 372: * no newsgroups are distribution 373: * names, and user simply will 374: * not type a valid distribution, 375: * assume that the default is OK. 376: */ 377: distribution[0] = '\0'; 378: return; 379: } 380: lastgroup = r; 381: if (once) 382: printf("Sorry, '%s' is an unknown distribution. Type ? for help.\n", def); 383: once = FALSE; 384: strcpy(def, r); 385: r = index(def, NGDELIM); 386: if (r) 387: *r = '\0'; 388: r = index(def, '.'); 389: } while (r == NULL); 390: *r = '\0'; 391: if (strcmp(def, "net") == 0) 392: strcpy(def, "world"); 393: } 394: } 395: } 396: 397: /* 398: * Do sanity checks before the author types in the message. 399: */ 400: pre_checks() 401: { 402: if (recording(newsgroups)) 403: return 1; 404: return 0; 405: } 406: 407: /* 408: * Check to see if the newsgroup is moderated. 409: */ 410: check_mod() 411: { 412: register FILE *fd; 413: char ng[BUFLEN], mod[BUFLEN]; 414: 415: ismod = 0; 416: (void) sprintf(buf, "%s/%s", LIB, "moderators"); 417: fd = xfopen(buf, "r"); 418: 419: while (fgets(buf, sizeof buf, fd) != NULL) { 420: twosplit(buf, ng, mod); 421: if (ngmatch(newsgroups, ng)) { 422: (void) strcpy(moderator, mod); 423: ismod = 1; 424: } 425: } 426: (void) fclose(fd); 427: } 428: 429: /* 430: * Set up the temp file with headers. 431: */ 432: prep_article() 433: { 434: FILE *tf, *of; 435: struct stat stbuf; 436: 437: (void) strcpy(tempfname, "/tmp/postXXXXXX"); 438: (void) mktemp(tempfname); 439: 440: /* insert a header */ 441: tf = xfopen(tempfname, "w"); 442: fprintf(tf, "Subject: %s\n", subject); 443: fprintf(tf, "Newsgroups: %s\n", newsgroups); 444: if (distribution[0] != '\0') 445: fprintf(tf, "Distribution: %s\n", distribution); 446: if (ismod) 447: fprintf(tf, "To: %s\n", moderator); 448: 449: if (keywords[0] != '\0') 450: fprintf(tf, "Keywords: %s\n", keywords); 451: if (summary[0] != '\0') 452: fprintf(tf, "Summary: %s\n", summary); 453: 454: if (references[0] != '\0') { 455: fprintf(tf, "References: %s\n\n", references); 456: 457: if (askyes("Do you want to include a copy of the article? ", "no")){ 458: of = xfopen(original, "r"); 459: while (fgets(buf, BUFSIZ, of) != NULL) 460: if (buf[0] == '\n') /* skip headers */ 461: break; 462: fprintf(tf, "In article %s, %s writes:\n", msgid, isfrom); 463: while (fgets(buf, BUFSIZ, of) != NULL) 464: fprintf(tf, "> %s", buf); 465: (void) fclose(of); 466: printf("OK, but please edit it to suppress unnecessary verbiage, signatures, etc.\n"); 467: } 468: } 469: 470: fprintf(tf, "\n\n"); 471: (void) fflush(tf); 472: (void) fstat(fileno(tf), &stbuf); 473: fmodtime = stbuf.st_mtime; 474: (void) fclose(tf); 475: } 476: 477: edit_article() 478: { 479: register char *p; 480: char *editor; 481: char *endflag = ""; 482: char *getenv(); 483: 484: /* edit the file */ 485: editor = getenv("EDITOR"); 486: if (editor == NULL) 487: editor = DFTEDITOR; 488: 489: p = editor + strlen(editor) - 2; 490: if (strcmp(p, "vi") == 0) 491: endflag = "+"; 492: 493: (void) sprintf(buf, "A=%s;export A;exec %s %s %s", 494: original, editor, endflag, tempfname); 495: 496: (void) system(buf); 497: } 498: 499: /* 500: * Do sanity checks after the author has typed in the message. 501: */ 502: post_checks() 503: { 504: char group[BUFLEN]; 505: register char *c, *p; 506: struct stat stbuf; 507: 508: if (stat(tempfname, &stbuf) < 0) { 509: printf("File deleted - no message posted.\n"); 510: (void) UNLINK(tempfname); 511: exit(1); 512: } 513: 514: if (stbuf.st_mtime == fmodtime || stbuf.st_size < 5) { 515: printf("File not modified - no message posted.\n"); 516: (void) UNLINK(tempfname); 517: exit(1); 518: } 519: 520: /* 521: * Is this the right number? Most of the headers are yet to be added 522: */ 523: if (stbuf.st_size > 65000) { 524: printf("\nYour message will probably be truncated when it\n"); 525: printf("passes through a notesfile site, since it is\n"); 526: printf("greater than 65000 characters.\n\n"); 527: if (!askyes("Do you still want to post it? ","")) { 528: sprintf(ccname, "%s/dead.article", homedir); 529: save_article(); 530: (void) UNLINK(tempfname); 531: exit(1); 532: } 533: } 534: 535: /* 536: * get the newsgroups from the edited article, in 537: * case they were altered in the editor 538: */ 539: if (!article_line(tempfname, "Newsgroups: ", group)) { 540: nogroups: 541: printf("Not sending to any newsgroups - no message posted\n"); 542: (void) UNLINK(tempfname); 543: exit(1); 544: } 545: c = &group[11]; 546: while (*c == ' ' || *c == '\t') 547: c++; 548: if (*c == '\0') 549: goto nogroups; 550: for (p = newsgroups; *c; c++) /* copy to newsgroups, w/o blanks */ 551: if (*c != ' ' && *c != '\t') 552: *p++ = *c; 553: *p = '\0'; 554: 555: /* Sanity checks for certain newsgroups */ 556: if (ngmatch(newsgroups, "all.wanted") && ngmatch(distribution,"net,na,usa,att,btl,eunet,aus")) { 557: printf("Is your message something that might go in your local\n"); 558: printf("newspaper, for example a used car ad, or an apartment\n"); 559: printf("for rent? "); 560: if (askyes("","")) { 561: printf("It's pointless to distribute your article widely, since\n"); 562: printf("people more than a hundred miles away won't be interested.\n"); 563: printf("Please use a more restricted distribution.\n"); 564: get_distribution("*None*"); 565: modify_article(tempfname, "Distribution: ", distribution,REPLACE); 566: } 567: } 568: 569: if (ngmatch(newsgroups, "all.jokes")) { 570: if (askyes("Could this be offensive to anyone? ","")) { 571: getpr("Whom might it offend? ", group); 572: (void) sprintf(buf," - offensive to %s (rot 13)",group); 573: modify_article(tempfname, "Subject: ", buf, APPEND); 574: encode(tempfname); 575: } 576: } 577: 578: if (ngmatch(newsgroups, "net.general")) { 579: if (index(newsgroups, NGDELIM)) { 580: printf("Everybody in the world reads net.general, so it doesn't make\n"); 581: printf("sense to post to newsgroups in addition to net.general. If your\n"); 582: printf("article belongs in one of these other newsgroups, then you\n"); 583: printf("should not post to net.general. If it is important enough\n"); 584: printf("for net.general, then you shouldn't post it in other places\n"); 585: printf("as well. Please reenter the newsgroups.\n"); 586: while (!get_newsgroup()) 587: ; 588: modify_article(tempfname, "Newsgroups: ", newsgroups,REPLACE); 589: } 590: if (ngmatch(newsgroups, "net.general")) { 591: printf("net.general is for important announcements.\n"); 592: printf("It is not for items for which you couldn't think\n"); 593: printf("of a better place - those belong in net.misc.\n"); 594: if (!askyes("Are you sure your message belongs in net.general? ","")) { 595: while (!get_newsgroup()) 596: ; 597: modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE); 598: } 599: } 600: } 601: 602: if (ngmatch(newsgroups, "net.sources,!net.sources.all")) { 603: if (!article_line(tempfname, "Subject: ", group)) { 604: nosubj: 605: printf("There seems to be no subject for this article.\n"); 606: getpr("Subject: ", subject); 607: modify_article(tempfname, "Subject: ", subject, REPLACE); 608: } else { 609: c = &group[8]; 610: while (*c == ' ' || *c == '\t') 611: c++; 612: if (*c == '\0') 613: goto nosubj; 614: strcpy(subject, c); 615: } 616: if (ngmatch(newsgroups, "all.wanted") || iswanted(subject)) { 617: printf("Requests for sources should not be posted to any of\n"); 618: printf("the net.sources newsgroups, please post such requests\n"); 619: printf("to net.wanted.sources only. Please reenter the newsgroups.\n\n"); 620: while (!get_newsgroup()) 621: ; 622: modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE); 623: } 624: if (ngmatch(newsgroups, "net.sources")) { 625: if (!ngmatch(newsgroups, "net.sources.all") && 626: stbuf.st_size < (4*1024)) { 627: printf("Your article seems rather small to be a source distribution.\n"); 628: if (!askyes("Are you certain that this is really source? ", "")) { 629: 630: while (!get_newsgroup()) 631: ; 632: modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE); 633: } 634: } 635: if (index(newsgroups, NGDELIM)) { 636: printf("Sources should be posted to one newsgroup only.\n"); 637: printf("Please pick the most appropriate group for your article.\n\n"); 638: while (!get_newsgroup()) 639: ; 640: modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE); 641: } 642: } 643: } 644: check_mod(); 645: } 646: 647: iswanted(str) 648: register char *str; 649: { 650: while (*str == ' ') 651: str++; 652: 653: if (prefix(str, "Re:")) 654: return (FALSE); 655: 656: if (isin(str, " wanted ") || isin(str, " can any") || 657: isin(str, " need ") || isin(str, " please ") || isin(str, " help ") 658: || isin(str, " looking ") || index(str, '?')) 659: return (TRUE); 660: 661: return (FALSE); 662: } 663: 664: isin(str, words) 665: register char *str, *words; 666: { 667: register char *p; 668: register sc, wc; 669: 670: p = words; 671: while (sc = *str++) { 672: if ((wc = *p++) == '\0') 673: return (TRUE); 674: if (wc == ' ') { 675: if (index(".,!?-; \t\n", sc)) 676: continue; 677: } else { 678: if (isupper(wc)) 679: wc = tolower(wc); 680: if (isupper(sc)) 681: sc = tolower(sc); 682: if (wc == sc) 683: continue; 684: } 685: str -= p - words - 1; 686: p = words; 687: } 688: if (*p == '\0') 689: return (TRUE); 690: return (FALSE); 691: } 692: 693: /* 694: * Save a copy of the article in the users NEWSARCHIVE directory. 695: */ 696: save_article() 697: { 698: FILE *in, *out; 699: int c; 700: time_t timenow, time(); 701: char *today, *ctime(); 702: struct stat stbuf; 703: char filename[BUFLEN]; 704: 705: if (stat(ccname, &stbuf) == 0 && (stbuf.st_mode&S_IFMT) == S_IFDIR) { 706: /* 707: * It would be much nicer here to write articles 708: * in MH format (numbered files, in rfc822 format) 709: * 710: * one day .. 711: */ 712: (void) sprintf(filename, "%s/author_copy", ccname); 713: (void) strcpy(ccname, filename); 714: } 715: in = xfopen(tempfname, "r"); 716: out = xfopen(ccname, "a"); 717: timenow = time((time_t)0); 718: today = ctime(&timenow); 719: fprintf(out,"From postnews %s",today); 720: while ((c=getc(in)) != EOF) 721: putc(c, out); 722: putc('\n', out); 723: (void) fclose(in); 724: (void) fclose(out); 725: } 726: 727: /* 728: * Post the article to the net. 729: */ 730: post_article() 731: { 732: int status; 733: 734: printf("%s article...\n", ismod ? "Mailing" : "Posting" ); 735: fflush(stdout); 736: if (ismod) 737: (void) sprintf(buf, "exec %s -t < %s", MAILPARSER, tempfname); 738: else 739: (void) sprintf(buf, "exec %s/%s -h < %s", LIB, "inews", tempfname); 740: status = system(buf); 741: 742: if (status) { 743: printf("Article not %s - exit status %d\n", ismod ? "mailed" : "posted", status); 744: return; 745: } else 746: printf("Article %s successfully.\n", ismod ? "mailed" : "posted" ); 747: 748: if (ccname[0]) { 749: printf("A copy has been saved in %s\n", ccname); 750: save_article(); 751: } 752: 753: (void) UNLINK(tempfname); 754: exit(0); 755: } 756: 757: /* 758: * Initialization. 759: */ 760: init() 761: { 762: FILE *fd; 763: register char *p; 764: int i; 765: char *getenv(); 766: struct passwd *pw; 767: 768: references[0] = '\0'; 769: distribution[0] = '\0'; 770: 771: uid = getuid(); 772: pw = getpwuid(uid); 773: if (pw == NULL) { 774: fprintf(stderr,"You're not in /etc/passwd\n"); 775: exit(1); 776: } 777: p = getenv("HOME"); 778: if (p == NULL) { 779: p = getenv("LOGDIR"); 780: if (p == NULL) 781: p = pw->pw_dir; 782: } 783: (void) strncpy(user, pw->pw_name, SBUFLEN); 784: (void) strcpy(homedir, p); 785: 786: p = getenv("NEWSARCHIVE"); 787: if (p != NULL) { 788: if (*p == '\0') 789: sprintf(ccname, "%s/author_copy", homedir); 790: else 791: strcpy(ccname, p); 792: } 793: 794: pathinit(); 795: (void) sprintf(buf, "%s/%s", LIB, "distributions"); 796: fd = xfopen(buf, "r"); 797: for (i=0; !feof(fd); i++) { 798: if (fgets(buf, sizeof buf, fd) == NULL) 799: break; 800: twosplit(buf, distr[i].abbr,distr[i].descr); 801: } 802: (void) fclose(fd); 803: } 804: 805: /* 806: * Split a line of the form 807: * text whitespace text 808: * into two strings. Also trim off any trailing newline. 809: * This is destructive on src. 810: */ 811: twosplit(src, dest1, dest2) 812: char *src, *dest1, *dest2; 813: { 814: register char *p; 815: 816: (void) nstrip(src); 817: for (p=src; isalnum(*p) || ispunct(*p); p++) 818: ; 819: *p++ = 0; 820: for ( ; isspace(*p); p++) 821: ; 822: (void) strcpy(dest1, src); 823: (void) strcpy(dest2, p); 824: } 825: 826: /* 827: * Get a yes or no answer to a question. A default may be used. 828: */ 829: askyes(msg, def) 830: char *msg, *def; 831: { 832: for(;;) { 833: printf("%s", msg); 834: buf[0] = 0; 835: (void) gets(buf); 836: switch(buf[0]) { 837: case 'y': 838: case 'Y': 839: return TRUE; 840: case 'n': 841: case 'N': 842: return FALSE; 843: case '\0': 844: switch(*def) { 845: case 'y': 846: case 'Y': 847: return TRUE; 848: case 'n': 849: case 'N': 850: return FALSE; 851: } 852: default: 853: printf("Please answer yes or no.\n"); 854: } 855: } 856: } 857: 858: /* 859: * Get a character string into buf, using prompt msg. 860: */ 861: getpr(msg, bptr) 862: char *msg, *bptr; 863: { 864: static int numeof = 0; 865: printf("%s", msg); 866: (void) gets(bptr); 867: (void) nstrip(bptr); 868: if (feof(stdin)) { 869: if (numeof++ > 3) { 870: fprintf(stderr,"Too many EOFs\n"); 871: exit(1); 872: } 873: clearerr(stdin); 874: } 875: } 876: 877: byebye(mesg) 878: char *mesg; 879: { 880: printf("%s\n", mesg); 881: exit(1); 882: } 883: 884: /* 885: * make a modification to the header of an article 886: * 887: * fname -- name of article 888: * field -- header field to modify 889: * line -- modification line 890: * how -- APPEND or REPLACE 891: * 892: * example: 893: * modify_article("/tmp/article" , "Subject:" , "new subject" , REPLACE); 894: * 895: * 896: */ 897: modify_article(fname, field, line, how) 898: char *fname, *field, *line; 899: { 900: FILE *fpart, *fptmp; 901: char *temp2fname = "/tmp/postXXXXXX"; 902: char lbfr[BUFLEN]; 903: register found = FALSE; 904: 905: mktemp(temp2fname); 906: 907: fptmp = xfopen(temp2fname, "w"); 908: fpart = xfopen(fname, "r"); 909: 910: while (fgets(lbfr, BUFLEN, fpart) != NULL) { 911: if (prefix(lbfr, field)) { 912: found = TRUE; 913: (void) nstrip(lbfr); 914: if (how == APPEND) { 915: /* append to current field */ 916: (void) strcat(lbfr, line); 917: (void) strcat(lbfr, "\n"); 918: } else 919: /* replace current field */ 920: (void) sprintf(lbfr, "%s%s\n", field, line); 921: } 922: (void) fputs(lbfr, fptmp); 923: } 924: 925: fclose(fpart); 926: fclose(fptmp); 927: 928: fptmp = xfopen(temp2fname, "r"); 929: fpart = xfopen(fname, "w"); 930: 931: if (!found) 932: fprintf(fpart, "%s%s\n", field, line); 933: while (fgets(buf,BUFLEN,fptmp) != NULL) 934: (void) fputs(buf, fpart); 935: 936: (void) fclose(fpart); 937: (void) fclose(fptmp); 938: (void) UNLINK(temp2fname); 939: } 940: 941: 942: /* verify that newsgroup exists, and get number of entries */ 943: valid_ng(ng, maxart, minart, canpost) 944: char *ng; 945: long *maxart, *minart; 946: char *canpost; 947: { 948: char ng_check[BUFLEN], ng_read[BUFLEN]; 949: FILE *fp; 950: 951: fp = xfopen(ACTIVE, "r"); 952: while (fgets(ng_read, BUFLEN, fp) != NULL) { 953: switch (sscanf(ng_read, "%s %ld %ld %c", ng_check, maxart, minart, canpost)) { 954: case 2: 955: *minart = 1; 956: /* fall through */ 957: case 3: 958: *canpost = 'y'; 959: /* fall through */ 960: case 4: 961: break; 962: 963: default: 964: printf("Active file (%s) corrupted. ", ACTIVE); 965: byebye("Seek help!"); 966: } 967: 968: if (strcmp(ng_check, ng) == 0) { 969: (void) fclose(fp); 970: if (*canpost == 'y') { 971: #ifdef FASCIST 972: if (uid && uid != ROOTID && fascist(user, ng)) { 973: *canpost = 'n'; 974: return FALSE; 975: } 976: #endif FASCIST 977: return TRUE; 978: } else 979: return FALSE; 980: } 981: } 982: *canpost = 'i'; 983: *maxart = 0; 984: *minart = 0; 985: (void) fclose(fp); 986: return FALSE; 987: } 988: 989: /* get the line specified by field from an article */ 990: article_line(article, field, line) 991: char *article, *field, *line; 992: { 993: FILE *fp; 994: char *c; 995: 996: fp = xfopen(article,"r"); 997: while ((c=fgets(line,BUFLEN,fp)) != NULL && !prefix(line, field)) 998: if (line[0] == '\n') { 999: c = NULL; 1000: break; 1001: } 1002: (void) fclose(fp); 1003: if (c != NULL) { 1004: (void) nstrip(line); 1005: return TRUE; 1006: } else { 1007: line[0] = '\0'; 1008: return FALSE; 1009: } 1010: } 1011: 1012: /* get the header information for a followup article */ 1013: followup(baseart) 1014: register char *baseart; 1015: { 1016: register char *p; 1017: 1018: /* subject */ 1019: if (article_line(baseart, "Subject: ", buf)) { 1020: p = buf+9; 1021: for ( ; ; ) { 1022: while (*p == ' ' || *p == '\t') 1023: ++p; 1024: if ((*p != 'r' && *p != 'R') || 1025: (p[1] != 'e' && p[1] != 'E') || 1026: (p[2] != ':' && p[2] != ' ')) 1027: break; 1028: p += 3; 1029: } 1030: (void) sprintf(subject, "Re: %s", p); 1031: } else { 1032: if (article_line(baseart, "From: ", buf)) 1033: (void) sprintf(subject, "Re: orphan response from %s", buf); 1034: else 1035: (void) strcpy(subject, "Re: orphan response"); 1036: } 1037: 1038: /* newsgroup */ 1039: if (article_line(baseart, "Newsgroups: ", buf)) 1040: (void) strcpy(newsgroups, buf+12); 1041: if (ngmatch(newsgroups, "net.general")) 1042: (void) strcpy(newsgroups,"net.followup"); 1043: if (ngmatch(newsgroups, "net.sources,!net.sources.all")) 1044: (void) strcpy(newsgroups,"net.sources.d"); 1045: if (ngmatch(newsgroups, "net.jobs")) { 1046: printf("net.jobs is for the direct posting of job announcements and requests.\n"); 1047: printf("it is not for discussion. You followup has been directed to net.misc\n"); 1048: (void) strcpy(newsgroups,"net.misc"); 1049: } 1050: 1051: /* moderator */ 1052: check_mod(); 1053: 1054: /* distribution */ 1055: if (article_line(baseart, "Distribution: ", buf)) 1056: (void) strcpy(distribution, buf+14); 1057: 1058: /* references */ 1059: if (article_line(baseart, "References: ", buf)) { 1060: register char *rcp; 1061: (void) strcpy(references, buf+12); 1062: (void) strcat(references, " "); 1063: /* keep the number of references to a reasonable number */ 1064: rcp = rindex(references, ' '); /* Can not fail */ 1065: while ((int)(rcp - references) > 70) { 1066: while (*--rcp != ' ') 1067: ; 1068: rcp[1] = '\0'; 1069: } 1070: } 1071: if (article_line(baseart, "Message-ID: ", buf)) { 1072: (void) strcat(references, buf+12); 1073: (void) strcpy(msgid, buf+12); 1074: } 1075: 1076: if (article_line(baseart, "From: ", buf)) 1077: (void) strcpy(isfrom, buf+6); 1078: 1079: if (article_line(baseart, "Keywords: ", buf)) 1080: (void) strcpy(keywords, buf+10); 1081: 1082: if (article_line(baseart, "Followup-To: ", buf)) { 1083: (void) strcpy(newsgroups, buf+13); 1084: if (strcmp(newsgroups, "poster") == 0) 1085: byebye("Mail followups directly to poster."); 1086: } 1087: 1088: get_summary(); 1089: } 1090: 1091: get_summary() 1092: { 1093: register char *p; 1094: register i; 1095: 1096: printf("Please enter a short summary of your contribution to the discussion\n"); 1097: printf("Just one or two lines ... (end with a blank line)\n"); 1098: p = summary; 1099: for (i = 0; i < 3; i++) { /* 3 * 80 < 256, should be safe .. */ 1100: getpr(">\t", p); 1101: if (*p == '\0') 1102: break; 1103: p = index(p, '\0'); 1104: (void) strcpy(p, "\n\t "); 1105: p += 3; 1106: } 1107: if (p > summary) 1108: p[-3] = '\0'; 1109: } 1110: 1111: encode(article) 1112: char *article; 1113: { 1114: FILE *fpart, *fphead, *fpcoded; 1115: char *headerfile = "/tmp/pheadXXXXXX"; 1116: char *codedfile = "/tmp/pcodeXXXXXX"; 1117: 1118: (void) mktemp(headerfile); 1119: (void) mktemp(codedfile); 1120: 1121: fpart = xfopen(article, "r"); 1122: 1123: /* place article header in "headerfile" file */ 1124: fphead = xfopen(headerfile, "w"); 1125: while (fgets(buf, BUFLEN, fpart) != NULL) { 1126: (void) fputs(buf, fphead); 1127: if (buf[0] == '\n') 1128: break; 1129: } 1130: (void) fclose(fphead); 1131: 1132: /* place article body in "codedfile" file */ 1133: fpcoded = xfopen(codedfile, "w"); 1134: while (fgets(buf, BUFLEN, fpart) != NULL) 1135: (void) fputs(buf, fpcoded); 1136: (void) fclose(fpcoded); 1137: (void) fclose(fpart); 1138: 1139: /* encode body and put back together with header */ 1140: (void) rename(headerfile, article); 1141: 1142: (void) sprintf(buf,"exec %s/%s 13 < %s >> %s\n", LIB, "caesar", codedfile, article); 1143: printf("Encoding article -- please stand by\n"); 1144: if (system(buf)) { 1145: printf("encoding failed"); 1146: exit(2); 1147: } 1148: (void) UNLINK(codedfile); 1149: } 1150: 1151: 1152: /* 1153: * Print a recorded message warning the poor luser what he is doing 1154: * and demand that he understands it before proceeding. Only do 1155: * this for newsgroups listed in LIBDIR/recording. 1156: */ 1157: recording(ngrps) 1158: char *ngrps; 1159: { 1160: char recbuf[BUFLEN]; 1161: FILE *fd; 1162: char nglist[BUFLEN], fname[BUFLEN]; 1163: int c, n, yes, retval = 0; 1164: 1165: (void) sprintf(recbuf, "%s/%s", LIB, "recording"); 1166: fd = fopen(recbuf, "r"); 1167: if (fd == NULL) 1168: return 0; 1169: while ((fgets(recbuf, sizeof recbuf, fd)) != NULL) { 1170: (void) sscanf(recbuf, "%s %s", nglist, fname); 1171: if (ngmatch(ngrps, nglist)) { 1172: (void) fclose(fd); 1173: if (fname[0] == '/') 1174: (void) strcpy(recbuf, fname); 1175: else 1176: (void) sprintf(recbuf, "%s/%s", LIB, fname); 1177: fd = fopen(recbuf, "r"); 1178: if (fd == NULL) 1179: return 0; 1180: while ((c = getc(fd)) != EOF) 1181: putc(c, stderr); 1182: fprintf(stderr, "Do you understand this? Hit <return> to proceed, <BREAK> to abort: "); 1183: n = read(2, recbuf, 100); 1184: c = recbuf[0]; 1185: yes = (c=='y' || c=='Y' || c=='\n' || c=='\n' || c==0); 1186: if (n <= 0 || !yes) 1187: retval = -1; 1188: } 1189: } 1190: return retval; 1191: } 1192: 1193: xxit(i) 1194: { 1195: exit(i); 1196: } 1197: 1198: #if !defined(BSD4_2) && !defined(BSD4_1C) 1199: rename(from,to) 1200: register char *from, *to; 1201: { 1202: (void) unlink(to); 1203: if (link(from, to) < 0) 1204: return -1; 1205: 1206: (void) unlink(from); 1207: return 0; 1208: } 1209: #endif /* !BSD4_2 && ! BSD4_1C */