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 */

Defined functions

article_line defined in line 990; used 13 times
askyes defined in line 829; used 8 times
byebye defined in line 877; used 4 times
check_mod defined in line 410; used 3 times
edit_article defined in line 477; used 1 times
encode defined in line 1111; used 1 times
followup defined in line 1013; used 2 times
get_distribution defined in line 280; used 2 times
get_newsgroup defined in line 217; used 6 times
get_summary defined in line 1091; used 1 times
getpr defined in line 861; used 11 times
init defined in line 760; used 1 times
  • in line 69
isin defined in line 664; used 6 times
iswanted defined in line 647; used 1 times
main defined in line 64; never used
modify_article defined in line 897; used 8 times
post_article defined in line 730; used 1 times
post_checks defined in line 502; used 1 times
pre_checks defined in line 400; used 1 times
prep_article defined in line 432; used 1 times
recording defined in line 1157; used 1 times
rename defined in line 1199; used 10 times
save_article defined in line 696; used 2 times
twosplit defined in line 811; used 2 times
valid_ng defined in line 943; used 2 times
xxit defined in line 1193; never used

Defined variables

Progname defined in line 51; never used
SccsId defined in line 21; never used
buf defined in line 55; used 71 times
ccname defined in line 35; used 9 times
distr defined in line 60; used 8 times
distribution defined in line 39; used 21 times
homedir defined in line 33; used 3 times
isfrom defined in line 43; used 2 times
ismod defined in line 54; used 7 times
keywords defined in line 45; used 4 times
moderator defined in line 42; used 2 times
msgid defined in line 44; used 2 times
newsgroups defined in line 41; used 35 times
ngsep defined in line 49; used 1 times
original defined in line 32; used 12 times
references defined in line 40; used 8 times
subject defined in line 38; used 12 times
summary defined in line 46; used 4 times
tempfname defined in line 31; used 28 times
uid defined in line 47; used 4 times
user defined in line 34; used 2 times

Defined struct's

distr defined in line 57; never used

Defined macros

APPEND defined in line 26; used 2 times
REPLACE defined in line 27; used 7 times
Last modified: 1986-03-20
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4793
Valid CSS Valid XHTML 1.0 Strict