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:  * ifuncs - functions used by inews.
  16:  */
  17: 
  18: #ifdef SCCSID
  19: static char *SccsId = "@(#)ifuncs.c	2.51	3/19/86";
  20: #endif /* SCCSID */
  21: 
  22: #include "iparams.h"
  23: #include <errno.h>
  24: #include <ctype.h>
  25: 
  26: /*LINTLIBRARY*/
  27: 
  28: #define AFSIZ   4000    /* size of text in the active file for initial malloc */
  29: 
  30: /*
  31:  * Transmit this article to all interested systems.
  32:  */
  33: 
  34: #ifdef u370
  35: static struct srec srec;
  36: #endif /* u370 */
  37: 
  38: static struct hbuf h, hh;
  39: 
  40: #ifdef MULTICAST
  41: #define MAXMCAST    20
  42: #define MAXMCS      10
  43: 
  44: struct multicast {
  45:     char mc_name[SBUFLEN];      /* "multi-cast" name */
  46:     short mc_syscnt;
  47:     char mc_tosys[MAXMCAST][SBUFLEN];
  48: } mcast[MAXMCS];
  49: 
  50: static int mccount;
  51: #endif /* MULTICAST */
  52: 
  53: #ifndef DBM
  54: char *histfile();
  55: #endif /* !DBM */
  56: 
  57: broadcast()
  58: {
  59:     register char *hptr;
  60:     register char *sptr;
  61:     register FILE *fp;
  62: #ifndef u370
  63:     struct srec srec;
  64: #endif
  65:     char sentbuf[LBUFLEN];
  66:     int nsent = 0;
  67:     char *sentsys;
  68: 
  69:     /* h is a local copy of the header we can scribble on */
  70:     fp = xfopen(ARTICLE, "r");
  71:     if (hread(&h, fp, TRUE) == NULL)
  72:         xerror("Cannot reread article");
  73:     (void) fclose(fp);
  74: 
  75:     (void) strcpy(sentbuf, h.ident);
  76:     (void) strcat(sentbuf, " sent to ");
  77:     sentsys = index(sentbuf, 0);
  78:     nsent = 0;
  79:     /* break path into list of systems. */
  80:     sptr = hptr = h.path;
  81:     while ((hptr=strpbrk(hptr, NETCHRS)) != NULL) {
  82:         *hptr++ = '\0';
  83:         sptr = hptr;
  84:     }
  85:     *sptr = '\0';
  86: 
  87: #ifdef MULTICAST
  88:     mccount = 0;
  89: #endif /* MULTICAST */
  90: 
  91:     /* loop once per system. */
  92:     s_openr();
  93:     while (s_read(&srec)) {
  94: #ifdef HIDDENNET
  95:         if (strncmp(srec.s_name, LOCALSYSNAME, SNLN) == 0)
  96:             continue;
  97: #endif /* HIDDENNET */
  98:         if (strncmp(srec.s_name, FULLSYSNAME, SNLN) == 0)
  99:             continue;
 100:         if (sptr = srec.s_nosend) {
 101:             while (*sptr) {
 102:                 while (*sptr && *sptr != ',')
 103:                     sptr++;
 104:                 if (*sptr == ',')
 105:                     *sptr++ = '\0';
 106:             }
 107:             *++sptr = '\0';
 108:         }
 109:         hptr = h.path;
 110:         while (*hptr != '\0') {
 111:             if (strncmp(srec.s_name, hptr, SNLN) == 0)
 112:                 goto contin;
 113:             if (sptr = srec.s_nosend) {
 114:                 while (*sptr != '\0') {
 115:                     if (strncmp(sptr, hptr, SNLN) == 0)
 116:                         goto contin;
 117:                     while (*sptr++)
 118:                         ;
 119:                 }
 120:             }
 121:             while (*hptr++ != '\0')
 122:                 ;
 123:         }
 124:         if (!ngmatch(h.nbuf, srec.s_nbuf))
 125:             continue;
 126:         if (h.distribution[0] != '\0' &&
 127:             !ngmatch(h.distribution, srec.s_nbuf) &&
 128:             !ngmatch(srec.s_nbuf, h.distribution))
 129:                 continue;
 130:         if (nsent) {
 131:             hptr = sentsys;
 132:             while ((sptr = index(hptr, ',')) != NULL) {
 133:                 *sptr = '\0';
 134:                 if (strcmp(hptr, srec.s_name) == 0) {
 135:                     *sptr = ',';
 136:                     goto contin;
 137:                 }
 138:                 *sptr++ = ',';
 139:                 for (hptr = sptr; isspace(*hptr); hptr++)
 140:                     ;
 141:             }
 142:             if (strcmp(hptr, srec.s_name) == 0)
 143:                 continue;
 144:         }
 145:         /* now we've found a system to send this article to */
 146: #ifdef MULTICAST
 147:         if (index(srec.s_flags, 'M')) {
 148:             /* do a "multi-cast" transmit */
 149:             register struct multicast *m;
 150: 
 151:             if (strlen(srec.s_name) >= SBUFLEN ||
 152:                 strlen(srec.s_xmit) >= SBUFLEN)
 153:                 xerror("system name too long for multicast");
 154:             for (m = mcast; m < &mcast[mccount]; m++)
 155:                 if (strcmp(srec.s_xmit, m->mc_name) == 0)
 156:                     break;
 157:             if (m >= &mcast[MAXMCS])
 158:                 xerror("Too many multicasts");
 159:             if (m == &mcast[mccount]) {
 160:                 mccount++;
 161:                 m->mc_syscnt = 0;
 162:                 strcpy(m->mc_name, srec.s_xmit);
 163:             }
 164:             if (m->mc_syscnt >= MAXMCAST)
 165:                 xerror("Too many systems for multicast");
 166:             strcpy(m->mc_tosys[m->mc_syscnt++], srec.s_name);
 167:         } else {
 168:             register struct multicast *m;
 169:             register char **yptr;
 170:             char *sysptrs[MAXMCAST];
 171:             int mc;
 172: 
 173:             mc = 0;
 174:             for (m = mcast; m < &mcast[mccount]; m++)
 175:                 if (strcmp(m->mc_name, srec.s_name) == 0) {
 176:                     yptr = sysptrs;
 177:                     while (mc < m->mc_syscnt)
 178:                         *yptr++ = m->mc_tosys[mc++];
 179:                     break;
 180:                 }
 181:             if (!transmit(&srec,xfopen(ARTICLE,"r"),1,sysptrs,mc))
 182:                 continue;
 183:         }
 184: #else /* !MULTICAST */
 185:         if (!transmit(&srec, xfopen(ARTICLE, "r"), 1, (char **)0, 0))
 186:             continue;
 187: #endif /* !MULTICAST */
 188:         if (nsent)
 189:             (void) strcat(sentbuf, ", ");
 190:         (void) strcat(sentbuf, srec.s_name);
 191:         nsent++;
 192:     contin:;
 193:     }
 194:     if (nsent)
 195:         log(sentbuf);
 196:     s_close();
 197: }
 198: 
 199: /*
 200:  * Transmit file to system.
 201:  */
 202: #define PROC 0004
 203: #ifndef MULTICAST
 204: /* ARGSUSED */
 205: #endif /* !MULTICAST */
 206: transmit(sp, ifp, maynotify, sysnames, mc)
 207: register struct srec *sp;
 208: register FILE *ifp;
 209: int maynotify;
 210: char **sysnames;
 211: int mc;
 212: {
 213:     register FILE *ofp;
 214:     register int c;
 215:     register char *ptr;
 216:     char TRANS[BUFLEN];
 217:     char *argv[20];
 218:     register int pid;
 219:     extern char firstbufname[];
 220: 
 221: /* A:	afmt: the other machine runs an A news, so we xmit in A format */
 222:     int afmt = (index(sp->s_flags, 'A') != NULL);
 223: /* B:	use B format (this is the default - don't use this letter elsewise). */
 224: /* F:	append name to file */
 225:     int appfile = (index(sp->s_flags, 'F') != NULL);
 226: /* L:	local: don't send the article unless it was generated locally */
 227:     int local = ((ptr = index(sp->s_flags, 'L')) != NULL);
 228: /* H:	interpolate history line into command, use existing file */
 229:     int history = (index(sp->s_flags, 'H') != NULL);
 230: /* M:	multi-cast: this is taken care of above, but don't reuse flag */
 231: #ifdef MULTICAST
 232: /* O:	multi-cast only, don't send article if not multicast hosts */
 233:     int multisend = (index(sp->s_flags, 'O') != NULL);
 234: #endif /* MULTICAST */
 235: /* N:	notify: don't send the article, just tell him we have it */
 236:     int notify = maynotify && (index(sp->s_flags, 'N') != NULL);
 237: /* S:	noshell: don't fork a shell to execute the xmit command */
 238:     int noshell = (index(sp->s_flags, 'S') != NULL);
 239: /* U:	useexist: use the -c option to uux to use the existing copy */
 240:     int useexist = (index(sp->s_flags, 'U') != NULL);
 241: 
 242:     if (local && mode == PROC) {
 243:         local = 0;
 244:         while (isdigit(*++ptr))
 245:             local = local * 10 + *ptr - '0';
 246:         for (ptr = h.path; *ptr != '\0' && local >= 0; local--)
 247:             while (*ptr++ != '\0')
 248:                 ;
 249:         if (local < 0) {
 250:             (void) fclose(ifp);
 251:             return FALSE;
 252:         }
 253:     }
 254: 
 255: #ifdef DEBUG
 256:     printf("Transmitting to '%s'\n", sp->s_name);
 257: #endif /* DEBUG */
 258: 
 259: #ifdef MULTICAST
 260:     if (multisend && mc == 0) {
 261:         (void) fclose(ifp);
 262:         return FALSE;
 263:     }
 264: #endif /* MULTICAST */
 265: 
 266:     if (!appfile && !useexist && !history) {
 267:         if (!hread(&hh, ifp, TRUE)) {
 268:             logerr("Bad header, not transmitting %s re %s to %s",
 269:                 hh.ident, hh.title, sp->s_name);
 270:             (void) fclose(ifp);
 271:             return FALSE;
 272:         }
 273:         if (hh.nbuf[0] == '\0') {
 274:             fprintf(stderr, "Article not subscribed to by %s\n", sp->s_name);
 275:             (void) fclose(ifp);
 276:             return FALSE;
 277:         }
 278:         (void) sprintf(TRANS, "%s/trXXXXXX", SPOOL);
 279:     }
 280: 
 281:     if (notify) {
 282:         char oldid[50];
 283:         (void) sprintf(hh.title, "ihave %s %s", hh.ident, FULLSYSNAME);
 284:         (void) sprintf(hh.nbuf, "to.%s.ctl", sp->s_name);
 285:         (void) strcpy(oldid, hh.ident);
 286:         getident(&hh);
 287:         log("tell %s about %s, notif. id %s",
 288:             sp->s_name, oldid, hh.ident);
 289:     }
 290: 
 291:     if (appfile) {
 292:         if (firstbufname[0] == '\0') {
 293:             extern char histline[];
 294:             localize("junk");
 295:             savehist(histline);
 296:             xerror("No file name to xmit from");
 297:         }
 298:         if (sp->s_xmit[0] == '\0')
 299:             sprintf(sp->s_xmit, "%s/%s", BATCHDIR, sp->s_name);
 300: #ifdef IHCC
 301:         (void) sprintf(TRANS, "%s/%s/%s", logdir(HOME), BATCHDIR, sp->s_xmit);
 302:         ofp = fopen(TRANS, "a");
 303: #else /* !IHCC */
 304:         ofp = fopen(sp->s_xmit, "a");
 305: #endif /* !IHCC */
 306:         if (ofp == NULL)
 307:             xerror("Cannot append to %s", sp->s_xmit);
 308: #ifdef MULTICAST
 309:         fprintf(ofp, "%s", firstbufname);
 310:         while (--mc >= 0)
 311:             fprintf(ofp, " %s", *sysnames++);
 312:         fprintf(ofp, "\n");
 313: #else /* !MULTICAST */
 314:         fprintf(ofp, "%s\n", firstbufname);
 315: #endif /* !MULTICAST */
 316:         (void) fclose(ofp);
 317:         (void) fclose(ifp);
 318:         return TRUE;
 319:     }
 320:     else if (useexist) {
 321:         if (firstbufname[0] == '\0')
 322:             xerror("No file name to xmit from");
 323:         if (*sp->s_xmit == '\0')
 324: #ifdef UXMIT
 325:             (void) sprintf(bfr, UXMIT, sp->s_name, firstbufname);
 326: #else
 327:             xerror("UXMIT not defined for U flag");
 328: #endif
 329:         else
 330: #ifdef MULTICAST
 331:             makeargs(bfr, sp->s_xmit, firstbufname, sysnames, mc);
 332: #else
 333:             (void) sprintf(bfr, sp->s_xmit, firstbufname);
 334: #endif
 335:         (void) fclose(ifp);
 336:     } else if (history) {
 337:         extern char histline[];
 338: 
 339:         if (*sp->s_xmit == '\0')
 340:             xerror("no xmit command with H flag");
 341: #ifdef MULTICAST
 342:         makeargs(bfr, sp->s_xmit, histline, sysnames, mc);
 343: #else
 344:         (void) sprintf(bfr, sp->s_xmit, histline);
 345: #endif
 346:     } else {
 347:         ofp = xfopen(mktemp(TRANS), "w");
 348:         if (afmt) {
 349: #ifdef OLD
 350:             fprintf(ofp, "A%s\n%s\n%s!%s\n%s\n%s\n", oident(hh.ident), hh.nbuf, FULLSYSNAME,
 351:                 hh.path, hh.subdate, hh.title);
 352: #else /* !OLD */
 353:             logerr("Must have OLD defined to use A flag for xmit");
 354:             return FALSE;
 355: #endif /* !OLD */
 356:         } else
 357:             hwrite(&hh, ofp);
 358:         if (!notify)
 359:             while ((c = getc(ifp)) != EOF)
 360:                 putc(c, ofp);
 361:         if (ferror(ofp))
 362:             xerror("write failed on transmit");
 363:         (void) fclose(ifp);
 364:         (void) fclose(ofp);
 365:         if (*sp->s_xmit == '\0')
 366:             (void) sprintf(bfr, DFTXMIT, sp->s_name, TRANS);
 367:         else
 368: #ifdef MULTICAST
 369:             makeargs(bfr, sp->s_xmit, TRANS, sysnames, mc);
 370: #else /* !MULTICAST */
 371:             (void) sprintf(bfr, sp->s_xmit, TRANS);
 372: #endif /* !MULTICAST */
 373:     }
 374: 
 375:     /* At this point, the command to be executed is in bfr. */
 376:     if (noshell) {
 377:         if (pid = fork())
 378:             fwait(pid);
 379:         else {
 380:             (void) close(0);
 381:             (void) open(TRANS, 0);
 382:             ptr = bfr;
 383:             for (pid = 0; pid < 19; pid++) {
 384:                 while (isspace(*ptr))
 385:                     *ptr++ = 0;
 386:                 argv[pid] = ptr;
 387:                 while (!isspace(*++ptr) && *ptr)
 388:                     ;
 389:                 if (!*ptr)
 390:                     break;
 391:             }
 392:             argv[++pid] = 0;
 393:             (void) setgid(gid);
 394:             (void) setuid(uid);
 395:             execv(argv[0], argv);
 396:             xerror("Can't execv %s", argv[0]);
 397:         }
 398:     } else {
 399:         if (!history && sp->s_xmit[0] && !index(bfr, '<')) {
 400:             char newcmd[LBUFLEN];
 401: 
 402:             (void) sprintf(newcmd, "(%s) <%s", bfr,
 403:                 useexist ? firstbufname : TRANS);
 404:             system(newcmd);
 405:         } else
 406:             system(bfr);
 407:     }
 408:     if (!appfile && !useexist && !history)
 409:         (void) unlink(TRANS);
 410:     (void) fclose(ifp);
 411:     return TRUE;
 412: }
 413: 
 414: #ifdef MULTICAST
 415: makeargs(buf, cmd, arg2, sysargs, sac)
 416: char *buf;
 417: char *cmd;
 418: char *arg2;
 419: register char **sysargs;
 420: int sac;
 421: {
 422:     register char *p = cmd;
 423:     register char *q;
 424:     register ac = 0;
 425:     register char *b = buf;
 426: 
 427:     q = p;
 428:     do {
 429:         if (q = index(q, ' '))
 430:             *q = '\0';
 431:         if (index(p, '%')) {
 432:             switch (++ac) {
 433:             case 1:
 434:                 while (--sac >= 0) {
 435:                     sprintf(b, p, *sysargs++);
 436:                     b = index(b, '\0');
 437:                 }
 438:                 break;
 439:             case 2:
 440:                 sprintf(b, p, arg2);
 441:                 b = index(b, '\0');
 442:                 break;
 443:             default:
 444:                 if (q)
 445:                     *q = ' ';
 446:                 xerror("badly formed command: %s", cmd);
 447:             }
 448:         } else {
 449:             strcpy(b, p);
 450:             b = index(b, '\0');
 451:         }
 452:         if (q) {
 453:             *q = ' ';
 454:             p = q;
 455:             while (isspace(*q))
 456:                 q++;
 457:         }
 458:     } while (q != NULL);
 459: }
 460: #endif /* MULTICAST */
 461: 
 462: typedef struct {
 463:     char *dptr;
 464:     int dsize;
 465: } datum;
 466: 
 467: /*
 468:  * Return TRUE if we have seen this file before, else FALSE.
 469:  */
 470: history(hp)
 471: struct hbuf *hp;
 472: {
 473: #ifdef DBM
 474:     datum lhs, rhs;
 475:     datum fetch();
 476: #else /* !DBM */
 477:     register FILE *hfp;
 478:     register char *p;
 479: #endif /* !DBM */
 480:     char lcident[BUFLEN];
 481:     extern char histline[];
 482: 
 483: #ifdef DEBUG
 484:     fprintf(stderr,"history(%s)\n", hp->ident);
 485: #endif /* DEBUG */
 486:     /*
 487: 	 * Make the article ID case insensitive.
 488: 	 */
 489:     (void) strcpy(lcident, hp->ident);
 490:     lcase(lcident);
 491: 
 492:     idlock(lcident);
 493: #ifdef DBM
 494:     initdbm(ARTFILE);
 495:     lhs.dptr = lcident;
 496:     lhs.dsize = strlen(lhs.dptr) + 1;
 497:     rhs = fetch(lhs);
 498:     if (rhs.dptr)
 499:         return(TRUE);
 500: #else /* !DBM */
 501:     hfp = xfopen(histfile(lcident), "r");
 502:     while (fgets(bfr, BUFLEN, hfp) != NULL) {
 503:         p = index(bfr, '\t');
 504:         if (p == NULL)
 505:             p = index(bfr, '\n');
 506:         if (p != NULL)  /* can happen if nulls in file */
 507:             *p = 0;
 508:         lcase(bfr);
 509: 
 510:         if (strcmp(bfr, lcident) == 0) {
 511:             (void) fclose(hfp);
 512:             idunlock();
 513: #ifdef DEBUG
 514:             fprintf(stderr,"history returns true\n");
 515: #endif /* DEBUG */
 516:             return TRUE;
 517:         }
 518:     }
 519:     (void) fclose(hfp);
 520: #endif /* !DBM */
 521:     histline[0] = '\0';
 522:     addhist(hp->ident);
 523:     addhist("\t");
 524: #ifdef DEBUG
 525:     fprintf(stderr,"history returns false\n");
 526: #endif
 527:     return FALSE;
 528: }
 529: 
 530: char histline[PATHLEN];
 531: 
 532: addhist(msg)
 533: char *msg;
 534: {
 535:     (void) strcat(histline, msg);
 536: }
 537: 
 538: savehist(hline)
 539: char *hline;
 540: {
 541:     register FILE *hfp;
 542:     datum lhs, rhs;
 543:     long fpos;
 544:     register char *p;
 545: 
 546:     hfp = xfopen(ARTFILE, "a");
 547:     fpos = ftell(hfp);
 548:     fprintf(hfp, "%s\n", hline);
 549:     (void) fclose(hfp);
 550: #ifdef DBM
 551:     /* We assume that history has already been called, calling dbminit. */
 552:     p = index(hline, '\t');
 553:     if (p)
 554:         *p = 0;
 555:     lcase(hline);
 556:     lhs.dptr = hline;
 557:     lhs.dsize = strlen(lhs.dptr) + 1;
 558:     rhs.dptr = (char *)&fpos;
 559:     rhs.dsize = sizeof fpos;
 560:     store(lhs, rhs);
 561: #else /* !DBM */
 562:     /* also append to proper history subfile */
 563:     hfp = xfopen(histfile(hline), "a");
 564:     fprintf(hfp, "%s\n", hline);
 565:     (void) fclose(hfp);
 566: #endif /* !DBM */
 567:     idunlock();
 568: }
 569: 
 570: /*
 571:  * Save partial news.
 572:  */
 573: /* ARGSUSED */
 574: newssave(fd, dummy)
 575: FILE *fd;
 576: char *dummy;
 577: {
 578:     register FILE *tofd, *fromfd;
 579:     char sfname[BUFLEN];
 580:     register int c;
 581:     time_t tim;
 582: 
 583:     if (fd == NULL)
 584:         fromfd = xfopen(INFILE, "r");
 585:     else
 586:         fromfd = fd;
 587:     (void) umask(savmask);
 588:     (void) setgid(gid);
 589:     (void) setuid(uid);
 590: 
 591:     (void) sprintf(sfname, "%s/%s", userhome, PARTIAL);
 592:     if ((tofd = fopen(sfname, "a")) == NULL)
 593:         xerror("Cannot save partial news in %s", sfname);
 594:     (void) time(&tim);
 595:     fprintf(tofd, "----- News saved at %s\n", arpadate(&tim));
 596:     while ((c = getc(fromfd)) != EOF)
 597:         putc(c, tofd);
 598:     (void) fclose(fromfd);
 599:     (void) fclose(tofd);
 600:     printf("News saved in %s\n", sfname);
 601:     xxit(1);
 602: }
 603: 
 604: /*
 605:  * Handle dates in header.
 606:  */
 607: 
 608: dates(hp)
 609: struct hbuf *hp;
 610: {
 611:     time_t edt;
 612: 
 613:     if (*hp->subdate) {
 614:         if (cgtdate(hp->subdate) < 0) {
 615:             xerror("Cannot parse submittal date '%s'", hp->subdate);
 616:         }
 617:     } else {
 618:         (void) time(&edt);
 619:         (void) strcpy(hp->subdate, arpadate(&edt));
 620:     }
 621: }
 622: 
 623: char lockname[80];
 624: idlock(str)
 625: char *str;
 626: {
 627:     register int i;
 628:     char tempname[80];
 629:     time_t now;
 630:     struct stat sbuf;
 631:     extern int errno;
 632: #ifdef  VMS
 633:     int fd;
 634: 
 635:     (void) sprintf(lockname, "/tmp/%s.l.1", str);
 636:     if ((fd = creat(lockname, 0444)) < 0) {
 637: #else /* !VMS */
 638:     (void) strcpy(tempname, "/tmp/LTMP.XXXXXX");
 639:     (void) mktemp(tempname);
 640:     (void) sprintf(lockname, "/tmp/L%s", str);
 641: #ifdef FOURTEENMAX
 642:     lockname[5 /* /tmp/ */ + 14] = '\0';
 643: #endif
 644:     i = creat(tempname, 0666);
 645:     if (i < 0)
 646:         xerror("Cannot creat %s: errno %d", tempname, errno);
 647:     (void) close(i);
 648:     while (link(tempname, lockname)) {
 649: #endif /* !VMS */
 650:         (void) time(&now);
 651:         i = stat(lockname, &sbuf);
 652:         if (i < 0) {
 653:             xerror("Directory permission problem in /tmp");
 654:         }
 655:         if (sbuf.st_mtime + 10*60 < now) {
 656:             (void) unlink(lockname);
 657:             logerr("Article %s locked up", str);
 658:             break;
 659:         }
 660:         log("waiting on lock for %s", lockname);
 661:         sleep((unsigned)60);
 662:     }
 663: #ifdef VMS
 664:     (void) close(fd);
 665: #endif
 666:     (void) unlink(tempname);
 667: }
 668: 
 669: idunlock()
 670: {
 671:     (void) unlink(lockname);
 672: }
 673: 
 674: /*
 675:  * Put a unique name into header.ident.
 676:  */
 677: getident(hp)
 678: struct hbuf *hp;
 679: {
 680:     long seqn;
 681:     register FILE *fp;
 682: 
 683:     lock();
 684:     fp = xfopen(SEQFILE, "r");
 685:     (void) fgets(bfr, BUFLEN, fp);
 686:     (void) fclose(fp);
 687:     seqn = atol(bfr) + 1;
 688: #ifdef  VMS
 689:     (void) unlink(SEQFILE);
 690: #endif /* VMS */
 691:     fp = xfopen(SEQFILE, "r+w");
 692:     fprintf(fp, "%ld\n", seqn);
 693:     (void) fclose(fp);
 694:     unlock();
 695: #ifdef HIDDENNET
 696:     if (strcmp(LOCALSYSNAME, FULLSYSNAME))
 697:         (void) sprintf(hp->ident, "<%ld@%s.%s%s>", seqn, LOCALSYSNAME, FULLSYSNAME,
 698:         MYDOMAIN);
 699:     else
 700: #endif /* !HIDDENNET */
 701:     (void) sprintf(hp->ident, "<%ld@%s%s>", seqn, FULLSYSNAME, MYDOMAIN);
 702: }
 703: 
 704: /*
 705:  * Check that header.nbuf contains only valid newsgroup names;
 706:  * exit with error if not valid.
 707:  *
 708:  */
 709: ngfcheck(isproc)
 710: int isproc;
 711: {
 712:     register char *s1, *s2;
 713:     register FILE *f;
 714:     register char *os1;
 715:     int ngroups = 1;
 716:     unsigned int ngsize = AFSIZ;
 717:     char tbuf[BUFLEN], *ngcheck;
 718: 
 719:     f = xfopen(ACTIVE, "r");
 720:     ngcheck = malloc(ngsize);
 721:     if (ngcheck == NULL)
 722:         xerror("Can't malloc the active file");
 723:     s1 = ngcheck;
 724:     while (fgets(bfr, BUFLEN, f) != NULL) {
 725:         os1 = s1;
 726:         for(s2 = bfr; *s2 != '\0' && *s2 != ' ';) {
 727:             if (s1 >= &ngcheck[ngsize-2]) {
 728:                 unsigned int offs = s1 - ngcheck;
 729:                 ngsize += LBUFLEN;
 730:                 ngcheck = realloc(ngcheck, ngsize);
 731:                 if (ngcheck == NULL)
 732:                     xerror("Can't realloc active file");
 733:                 s1 = ngcheck + offs;
 734:             }
 735:             *s1++ = *s2++;
 736:         }
 737:         *s1++ = '\0';
 738:         if (isproc) /* don't check to see if can post to this group */
 739:             continue;
 740:         while (*s2++ != '\0' && *s2 != ' ')
 741:             ;   /* skip max article number */
 742:         while (*s2++ != '\0' && *s2 != ' ')
 743:             ;   /* skip min article number */
 744:         if (*s2++ != '\0' && *s2 == 'n')
 745:             s1 = os1;   /* can't post to this group */
 746:     }
 747:     *s1++ = '\0';
 748:     *s1 = '\0';
 749:     (void) fclose(f);
 750: 
 751:     s1 = header.nbuf;
 752:     s2 = nbuf;
 753:     while (*s1 == NGDELIM || *s1 == ' ')
 754:         s1++;   /* skip leading junk */
 755:     do {
 756:         /* there shouldn't be blanks, but give the jerk a break */
 757:         if (*s1 == NGDELIM || *s1 == ' ') {
 758:             *s2++ = '\0';
 759:             while (*++s1 == NGDELIM || *s1 == ' ')
 760:                 ;   /* remove extra commas */
 761:             if (*s1 != '\0')
 762:                 ngroups++;
 763:         } else
 764:             *s2++ = *s1++;
 765:     } while (*s1 != '\0');
 766:     if (s2[-1] == NGDELIM)  /* strip trailing commas */
 767:         s2--;
 768:     *s2 = '\0';
 769: 
 770:     s1 = nbuf;
 771:     while (*s1 != '\0') {   /* for each newsgroup in header */
 772:         s2 = ngcheck;
 773:         while (*s2 != '\0') { /* for each newsgroup in active file */
 774:             if (strcmp(s1, s2) == 0)
 775:                 break;
 776:             while (*s2++ != '\0')
 777:                 ;
 778:         }
 779:         if (*s2 == '\0') {  /* not found. remove it */
 780:             if (!isproc) {
 781:                 logerr("Invalid news group '%s'", s1);
 782:                 newssave(stdin, (char *)NULL);
 783:             }
 784:             /* See if it's in our alias list */
 785:             f = xfopen(ALIASES,"r");
 786:             while (fscanf(f,"%s %s", tbuf, bfr) == 2
 787:                 && strcmp(s1, tbuf))
 788:                 ;
 789:             (void) fclose(f);
 790:             if (strcmp(s1, tbuf) == 0) {
 791:                 logerr("Aliased newsgroup '%s' to '%s'", s1, bfr);
 792:                 os1 = s1;
 793:                 s1 = nbuf;
 794:                 s2 = tbuf;
 795:                 while (s1 < os1) /* copy left part */
 796:                     *s2++ = *s1++;
 797:                 s1 = bfr;
 798:                 while (*s1 != '\0') /* copy alias */
 799:                     *s2++ = *s1++;
 800:                 *s2++ = '\0';
 801:                 s1 = os1;
 802:                 os1 = nbuf + (s2 - tbuf);
 803:                 while (*s1++ != '\0') /* skip old group */
 804:                     ;
 805:                 /* copy right part */
 806:                 tbufcpy(s2, s1);
 807:                 /* copy back to original buffer */
 808:                 tbufcpy(nbuf, tbuf);
 809:                 s1 = os1;
 810:             } else {
 811:                 logerr("Unknown newsgroup '%s' removed", s1);
 812:                 s2 = s1;
 813:                 while (*s2++ != '\0')   /* skip the bad one */
 814:                     ;
 815:                 tbufcpy(s1, s2);
 816:             }
 817:         } else { /* It's in our active file */
 818:             os1 = s1;
 819:             while (*s1++ != '\0')
 820:                 ;
 821:             /* check for local only distribution on incoming
 822: 			   newsgroups. This might occur if someone posted to
 823: 			   general,net.unix */
 824:             if(isproc && ngroups > 1 && index(os1, '.') == NULL
 825:                 && index(header.nbuf, '.') != NULL) {
 826:                 logerr("Local group '%s' removed", os1);
 827:                 tbufcpy(os1, s1);
 828:                 s1 = os1;
 829:             }
 830:         }
 831:     }
 832:     /*  remove any duplicates */
 833:     os1 = s1 = nbuf;
 834:     for(;;) {
 835:         if (*s1++ == '\0') {
 836:             if (*s1 == '\0')
 837:                 break;
 838:             s2 = s1;
 839:             while (*s2 != '\0') {
 840:                 if (strcmp(os1, s2) == 0) {
 841:                     logerr("Duplicate '%s' removed",os1);
 842:                     os1 = s2;
 843:                     while (*s2++ != '\0') /* skip it */
 844:                         ;
 845:                     tbufcpy(os1, s2);
 846:                 } else
 847:                     while (*s2++ != '\0')
 848:                         ;
 849:             }
 850:             os1 = s1;
 851:             s1[-1] = '\0';
 852:         }
 853:     }
 854:     if (nbuf[0] != '\0') {
 855:         s1 = header.nbuf;
 856:         s2 = nbuf;
 857:         do {
 858:             while (*s2 != '\0')
 859:                 *s1++ = *s2++;
 860:             *s1++ = NGDELIM;
 861:         } while (*++s2 != '\0');
 862:         *--s1 = '\0';
 863:         (void) free(ngcheck);
 864:         return FALSE;
 865:     }
 866:     (void) free(ngcheck);
 867:     return TRUE;
 868: }
 869: 
 870: tbufcpy(s1, s2)
 871: register char *s1, *s2;
 872: {
 873:     do {
 874:         while (*s2 != '\0')
 875:             *s1++ = *s2++;
 876:         *s1++ = '\0';
 877:     } while (*++s2 != '\0');
 878:     *s1 = '\0';
 879: }
 880: 
 881: 
 882: /*
 883:  * Figure out who posted the article (which is locally entered).
 884:  * The results are placed in the header structure hp.
 885:  */
 886: gensender(hp, logname)
 887: struct hbuf *hp;
 888: char *logname;
 889: {
 890:     register char *fn, *p;
 891:     char buf[BUFLEN];
 892:     char *fullname(), *getenv();
 893:     int fd, n;
 894: 
 895:     fn = getenv("NAME");
 896: 
 897:     if (fn == NULL) {
 898:         (void) sprintf(buf, "%s/%s", userhome, ".name");
 899:         fd = open(buf, 0);
 900:         if (fd >= 0) {
 901:             n = read(fd, buf, sizeof buf);
 902:             (void) close(fd);
 903:             if (n > 0 && buf[0] >= 'A') {
 904:                 fn = buf;
 905:                 for (p=fn; *p; p++)
 906:                     if (*p < ' ')
 907:                         *p = '\0';
 908:             }
 909:         }
 910:     }
 911: 
 912:     if (fn == NULL)
 913:         fn = fullname(logname);
 914: 
 915:     (void) sprintf(hp->path, "%s", logname);
 916:     (void) sprintf(hp->from, "%s@%s%s (%s)", logname, FULLSYSNAME, MYDOMAIN, fn);
 917: }
 918: 
 919: /*
 920:  * Trap interrupts.
 921:  */
 922: onsig(n)
 923: int n;
 924: {
 925:     static int numsigs = 0;
 926:     /*
 927: 	 * Most UNIX systems reset caught signals to SIG_DFL.
 928: 	 * This bad design requires that the trap be set again here.
 929: 	 * Unfortunately, if the signal recurs before the trap is set,
 930: 	 * the program will die, possibly leaving the lock in place.
 931: 	 */
 932:     if (++numsigs > 100) {
 933:         logerr("inews ran away looping on signal %d", n);
 934:         xxit(1);
 935:     }
 936:     (void) signal(n, onsig);
 937:     SigTrap = n;
 938: }
 939: 
 940: #ifdef BATCH
 941: /*
 942:  * If the stdin begins with "#", we assume we have been fed a batched
 943:  * shell script which looks like this:
 944:  *	#! rnews 1234
 945:  *	article with 1234 chars
 946:  *	#! rnews 4321
 947:  *	article with 4321 chars
 948:  *
 949:  * In this case we just exec the unbatcher and let it unpack and call us back.
 950:  *
 951:  * Note that there is a potential security hole here.  If the batcher is
 952:  * /bin/sh, someone could ship you arbitrary stuff to run as shell commands.
 953:  * The main protection you have is that the effective uid will be news, not
 954:  * uucp and not the super user.  (That, plus the fact that BATCH is set to
 955:  * "unbatch" as the system is distributed.)  If you want to run a batched link
 956:  * and you are security conscious, do not use /bin/sh as the unbatcher.
 957:  * the thing to do is to change BATCH in your localize.sh file from /bin/sh
 958:  * to some restricted shell which can only run rnews.
 959:  */
 960: checkbatch()
 961: {
 962:     int c;
 963: 
 964:     c = getc(stdin);
 965:     if (c != EOF)
 966:         (void) ungetc(c, stdin);
 967:     clearerr(stdin);
 968:     if (c == '#') {
 969:         char unbatcher[BUFLEN];
 970: 
 971:         (void) sprintf(unbatcher, "%s/%s", LIB, BATCH);
 972:         reset_stdin();
 973:         execl(unbatcher, "news-unpack", (char *)0);
 974:         xerror("Unable to exec shell to unpack news.");
 975:     }
 976: }
 977: 
 978: /*
 979:  * We've already done a read on stdin, and we want to seek back to the
 980:  * beginning.  We want the real file descriptor (beyond buffers) to
 981:  * reflect the true beginning.  Do whatever is necessary.
 982:  */
 983: reset_stdin()
 984: {
 985:     register FILE *ofd;
 986:     register int c;
 987:     char *ofdname;
 988:     long lseek();
 989: 
 990:     /* First try to seek back - if so, it's a cheap way back. */
 991:     if (lseek(0, 0L, 0) == 0L)
 992:         return;
 993: 
 994:     /* Can't seek, so have to copy input to a file and use that. */
 995:     ofdname = "/tmp/inewsXXXXXX";
 996:     (void) mktemp(ofdname);
 997:     ofd = fopen(ofdname, "w");
 998:     while ((c=getc(stdin)) != EOF)
 999:         putc(c, ofd);
1000:     if (ferror(ofd))
1001:         xerror("write failed on temp file %s", ofdname);
1002:     (void) fclose(stdin);
1003:     (void) fclose(ofd);
1004: 
1005:     /* Now for a few lower level hacks to reopen stdin and make
1006: 	 * absolutely sure that the right fd's are done for the exec.
1007: 	 */
1008:     (void) close(0);        /* make sure stdin is really closed. */
1009:     (void) open(ofdname, 0);    /* should return zero */
1010:     (void) unlink(ofdname);     /* to avoid cleaning it up later. */
1011: }
1012: #endif /* BATCH */
1013: 
1014: /*
1015:  *	Exit and cleanup.
1016:  */
1017: xxit(status)
1018: int status;
1019: {
1020:     (void) unlink(INFILE);
1021:     (void) unlink(ARTICLE);
1022:     while (lockcount > 0)
1023:         unlock();
1024:     idunlock();
1025:     exit(status);
1026: }
1027: 
1028: rwaccess(fname)
1029: char *fname;
1030: {
1031:     int fd;
1032: 
1033:     fd = open(fname, 2);
1034:     if (fd < 0)
1035:         return 0;
1036:     (void) close(fd);
1037:     return 1;
1038: }
1039: 
1040: exists(fname)
1041: char *fname;
1042: {
1043:     int fd;
1044: 
1045:     fd = open(fname, 0);
1046:     if (fd < 0)
1047:         return 0;
1048:     (void) close(fd);
1049:     return 1;
1050: }
1051: 
1052: int lockcount = 0;          /* no. of times we've called lock */
1053: 
1054: #ifdef  VMS
1055: 
1056: #define SUBLOCK "/tmp/netnews.lck.1"
1057: 
1058: /*
1059:  * Newsystem locking.
1060:  * These routines are different for VMS because we can not
1061:  * effectively simulate links, and VMS supports multiple
1062:  * version numbers of files
1063:  */
1064: lock()
1065: {
1066:     register int i;
1067:     register int fd;
1068: 
1069:     if (lockcount++ == 0) {
1070:         i = DEADTIME;
1071:         while ((fd = creat(SUBLOCK, 0444)) < 0) {
1072:             if (--i < 0) {
1073:                 (void) unlink(SUBLOCK);
1074:                 logerr("News system locked up");
1075:             }
1076:             if (i < -3)
1077:                 xerror("Unable to unlock news system");
1078:             sleep((unsigned)1);
1079:         }
1080:         (void) close(fd);
1081:     }
1082: }
1083: 
1084: unlock()
1085: {
1086:     if (--lockcount == 0)
1087:         (void) unlink(SUBLOCK);
1088: }
1089: 
1090: #else /* !VMS */
1091: 
1092: /*
1093:  * Newsystem locking.
1094:  */
1095: 
1096: #ifdef BSD4_2
1097: #include <sys/file.h>
1098: static int LockFd = -1;
1099: lock()
1100: {
1101:     LockFd = open(SUBFILE,0);
1102:     /* This will sleep until the other program releases the lock */
1103:     /* We may need to alarm out of this, but I don't think so */
1104:     (void) flock(LockFd, LOCK_EX);
1105: }
1106: 
1107: unlock()
1108: {
1109:     (void) flock(LockFd, LOCK_UN);
1110:     (void) close(LockFd);
1111: }
1112: #else /* !BSD4_2 */
1113: /* Why doesn't USG unix have file locking????? */
1114: lock()
1115: {
1116:     register int i;
1117:     extern int errno;
1118: 
1119:     if (lockcount++ == 0) {
1120:         i = DEADTIME;
1121:         while (link(SUBFILE, LOCKFILE)) {
1122:             if (errno != EEXIST)
1123:                 break;
1124:             if (--i < 0)
1125:                 xerror("News system locked up");
1126:             sleep((unsigned)1);
1127:         }
1128:     }
1129: }
1130: 
1131: unlock()
1132: {
1133:     if (--lockcount == 0)
1134:         (void) unlink(LOCKFILE);
1135: }
1136: #endif /* !BSD4_2 */
1137: #endif /* !VMS */
1138: 
1139: /*
1140:  * Generate the name of the person responsible for posting this article,
1141:  * in order to check that two articles were posted by the same person.
1142:  */
1143: char *
1144: senderof(hp)
1145: struct hbuf *hp;
1146: {
1147:     char *q, *tp;
1148:     char *tailpath();
1149: 
1150:     if (hp->sender[0])
1151:         tp = hp->sender;
1152:     else if (hp->from[0])
1153:         tp = hp->from;
1154:     else
1155:         tp = tailpath(hp);
1156: 
1157:     /* Remove full name */
1158:     q = index(tp, ' ');
1159:     if (q)
1160:         *q = '\0';
1161: 
1162:     q = malloc((unsigned)(strlen(tp) + 1));
1163:     (void) strcpy(q, tp);
1164:     return q;
1165: }

Defined functions

addhist defined in line 532; used 5 times
broadcast defined in line 57; used 2 times
checkbatch defined in line 960; used 1 times
dates defined in line 608; used 2 times
exists defined in line 1040; used 4 times
gensender defined in line 886; used 1 times
getident defined in line 677; used 3 times
history defined in line 470; used 8 times
idlock defined in line 624; used 1 times
idunlock defined in line 669; used 3 times
lock defined in line 1114; used 2 times
makeargs defined in line 415; used 3 times
newssave defined in line 574; used 2 times
ngfcheck defined in line 709; used 1 times
onsig defined in line 922; used 5 times
reset_stdin defined in line 983; used 1 times
rwaccess defined in line 1028; used 4 times
savehist defined in line 538; used 6 times
senderof defined in line 1143; used 3 times
tbufcpy defined in line 870; used 5 times
transmit defined in line 206; used 2 times
unlock defined in line 1131; used 5 times
xxit defined in line 1017; used 2 times

Defined variables

LockFd defined in line 1098; used 4 times
SccsId defined in line 19; never used
h defined in line 38; used 9 times
hh defined in line 38; used 16 times
histline defined in line 530; used 12 times
lockcount defined in line 1052; used 5 times
lockname defined in line 623; used 9 times
mcast defined in line 48; used 6 times
mccount defined in line 50; used 5 times
srec defined in line 35; used 22 times

Defined struct's

multicast defined in line 44; used 4 times

Defined macros

AFSIZ defined in line 28; used 1 times
MAXMCAST defined in line 41; used 3 times
MAXMCS defined in line 42; used 2 times
PROC defined in line 202; used 1 times
SUBLOCK defined in line 1056; used 3 times
Last modified: 1986-03-20
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3988
Valid CSS Valid XHTML 1.0 Strict