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:  * inews - insert, receive, and transmit news articles.
  16:  *
  17:  */
  18: 
  19: #ifdef SCCSID
  20: static char *SccsId = "@(#)inews.c	2.61	3/19/86";
  21: #endif /* SCCSID */
  22: 
  23: #include "iparams.h"
  24: #include <errno.h>
  25: 
  26: /* local defines for inews */
  27: 
  28: #define OPTION  0   /* pick up an option string */
  29: #define STRING  1   /* pick up a string of arguments */
  30: 
  31: #define UNKNOWN 0001    /* possible modes for news program */
  32: #define UNPROC  0002    /* Unprocessed input */
  33: #define PROC    0004    /* Processed input */
  34: #define CANCEL  0010    /* Cancel an article */
  35: #define CREATENG 0020   /* Create a new newsgroup */
  36: 
  37: char    forgedname[NAMELEN];    /* A user specified -f option. */
  38: extern char histline[];
  39: /* Fake sys line in case they forget their own system */
  40: struct srec dummy_srec = { "MEMEME", "", "all", "", "" };
  41: 
  42: char *Progname = "inews";   /* used by xerror to identify failing program */
  43: 
  44: struct {            /* options table. */
  45:     char    optlet;     /* option character. */
  46:     char    filchar;    /* if to pickup string, fill character. */
  47:     int flag;       /* TRUE if have seen this opt. */
  48:     int oldmode;    /* OR of legal input modes. */
  49:     int newmode;    /* output mode. */
  50:     char    *buf;       /* string buffer */
  51: } *optpt, options[] = { /*
  52: optlet	filchar		flag	oldmode	newmode		buf	*/
  53: 't',    ' ',        FALSE,  UNPROC, UNKNOWN,    header.title,
  54: 'n',    NGDELIM,    FALSE,  UNPROC, UNKNOWN,    header.nbuf,
  55: 'd',    '\0',       FALSE,  UNPROC, UNKNOWN,    header.distribution,
  56: 'e',    ' ',        FALSE,  UNPROC, UNKNOWN,    header.expdate,
  57: 'p',    '\0',       FALSE,  UNKNOWN,PROC,       filename,
  58: 'f',    '\0',       FALSE,  UNPROC, UNKNOWN,    forgedname,
  59: 'F',    ' ',        FALSE,  UNPROC, UNKNOWN,    header.followid,
  60: 'c',    '\0',       FALSE,  UNKNOWN,CANCEL,     filename,
  61: 'C',    '\0',       FALSE,  UNKNOWN,CREATENG,   header.nbuf,
  62: #define hflag   options[9].flag
  63: 'h',    '\0',       FALSE,  UNPROC, UNKNOWN,    filename,
  64: #define oflag   options[10].flag
  65: 'o',    '\0',       FALSE,  UNPROC, UNKNOWN,    header.organization,
  66: #define Mflag   options[11].flag
  67: 'M',    '\0',       FALSE,  UNPROC, UNKNOWN,    filename,
  68: 'a',    '\0',       FALSE,  UNPROC, UNKNOWN,    header.approved,
  69: '\0',   '\0',       0,  0,  0,      (char *)NULL
  70: };
  71: 
  72: FILE *mailhdr();
  73: char *genversion();
  74: extern int errno;
  75: 
  76: /*
  77:  *	Authors:
  78:  *		Matt Glickman	glickman@ucbarpa.Berkeley.ARPA
  79:  *		Mark Horton	mark@cbosgd.UUCP
  80:  *		Stephen Daniels	swd@mcnc.UUCP
  81:  *		Tom Truscott	trt@duke.UUCP
  82:  *	IHCC version adapted by:
  83:  *		Larry Marek	larry@ihuxf.UUCP
  84:  */
  85: main(argc, argv)
  86: int argc;
  87: register char **argv;
  88: {
  89:     int state;      /* which type of argument to pick up	*/
  90:     int tlen, len;  /* temps for string processing routine	*/
  91:     register char *ptr; /* pointer to rest of buffer		*/
  92:     int filchar;    /* fill character (state = STRING)	*/
  93:     char    *user = NULL, *home = NULL; /* environment temps	*/
  94:     struct passwd   *pw;    /* struct for pw lookup			*/
  95:     struct group    *gp;    /* struct for group lookup		*/
  96:     register int    i;
  97:     FILE    *mfd;       /* mail file file-descriptor		*/
  98:     char    cbuf[BUFLEN];   /* command buffer			*/
  99: 
 100:     /* uuxqt doesn't close all it's files */
 101:     for (i = 3; !close(i); i++)
 102:         ;
 103:     /* set up defaults and initialize. */
 104:     mode = UNKNOWN;
 105:     pathinit();
 106:     ptr = rindex(*argv, '/');
 107:     if (!ptr)
 108:         ptr = *argv - 1;
 109:     if (!strncmp(ptr+1, "rnews", 5)) {
 110:         mode = PROC;
 111: #ifdef NICENESS
 112:         nice(NICENESS);
 113: #endif /* NICENESS */
 114:     } else if (argc < 2)
 115:         goto usage;
 116: 
 117:     state = OPTION;
 118:     header.title[0] = header.nbuf[0] = filename[0] = '\0';
 119: 
 120:     /* check for existence of special files */
 121:     if (!rwaccess(ARTFILE)) {
 122:         mfd = mailhdr((struct hbuf *)NULL, exists(ARTFILE) ? "Unwritable files!" : "Missing files!");
 123:         if (mfd != NULL) {
 124: #ifdef HIDDENNET
 125:             fprintf(mfd,"System: %s.%s\n\nThere was a problem with %s!!\n", LOCALSYSNAME, FULLSYSNAME, ARTFILE);
 126: #else /* !HIDDENNET */
 127:             fprintf(mfd,"System: %s\n\nThere was a problem with %s!!\n", FULLSYSNAME, ARTFILE);
 128: #endif /* !HIDDENNET */
 129:             (void) sprintf(cbuf, "touch %s;chmod 666 %s", ARTFILE, ARTFILE);
 130:             (void) system(cbuf);
 131:             if (rwaccess(ARTFILE))
 132:                 fprintf(mfd, "The problem has been taken care of.\n");
 133:             else
 134:                 fprintf(mfd, "Corrective action failed - check suid bits.\n");
 135:             (void) mclose(mfd);
 136:         }
 137:     }
 138:     if (!rwaccess(ACTIVE)) {
 139:         mfd = mailhdr((struct hbuf *)NULL, exists(ACTIVE) ? "Unwritable files!" : "Missing files!");
 140:         if (mfd != NULL) {
 141: #ifdef HIDDENNET
 142:             fprintf(mfd,"System: %s.%s\n\nThere was a problem with %s!!\n", LOCALSYSNAME, FULLSYSNAME, ARTFILE);
 143: #else /* !HIDDENNET */
 144:             fprintf(mfd, "System: %s\n\nThere was a problem with %s!!\n", FULLSYSNAME, ACTIVE);
 145: #endif /* !HIDDENNET */
 146:             (void) sprintf(cbuf, "touch %s;chmod 666 %s", ACTIVE, ACTIVE);
 147:             (void) system(cbuf);
 148:             if (rwaccess(ACTIVE))
 149:                 fprintf(mfd, "The problem has been taken care of.\n");
 150:             else
 151:                 fprintf(mfd, "Corrective action failed - check suid bits.\n");
 152:             (void) mclose(mfd);
 153:         }
 154:     }
 155:     SigTrap = FALSE;    /* true if a signal has been caught */
 156:     if (mode != PROC) {
 157:         (void) signal(SIGHUP, onsig);
 158:         (void) signal(SIGINT, onsig);
 159:     }
 160:     savmask = umask(N_UMASK);   /* set up mask */
 161:     uid = getuid();
 162:     gid = getgid();
 163:     duid = geteuid();
 164:     dgid = getegid();
 165:     if (uid == 0 && duid == 0) {
 166:         /*
 167: 		 * Must go through with this kludge since
 168: 		 * some systems do not honor the setuid bit
 169: 		 * when root invokes a setuid program.
 170: 		 */
 171:         if ((pw = getpwnam(NEWSUSR)) == NULL)
 172:             xerror("Cannot get NEWSU pw entry");
 173: 
 174:         duid = pw->pw_uid;
 175:         if ((gp = getgrnam(NEWSGRP)) == NULL)
 176:             xerror("Cannot get NEWSG gr entry");
 177:         dgid = gp->gr_gid;
 178:         (void) setgid(dgid);
 179:         (void) setuid(duid);
 180:     }
 181: 
 182: #ifndef IHCC
 183:     /*
 184: 	 * We force the use of 'getuser()' to prevent forgery of articles
 185: 	 * by just changing $LOGNAME
 186: 	 */
 187:     if (isatty(fileno(stderr))) {
 188:         if ((user = getenv("USER")) == NULL)
 189:             user = getenv("LOGNAME");
 190:         if ((home = getenv("HOME")) == NULL)
 191:             home = getenv("LOGDIR");
 192:     }
 193: #endif
 194:     if (user == NULL || home == NULL)
 195:         getuser();
 196:     else {
 197:         if (username == NULL || username[0] == 0) {
 198:             username = AllocCpy(user);
 199:         }
 200:         userhome = AllocCpy(home);
 201:     }
 202:     getuser();
 203: 
 204:     /* loop once per arg. */
 205: 
 206:     ++argv;     /* skip first arg, which is prog name. */
 207: 
 208:     while (--argc) {
 209:         if (state == OPTION) {
 210:         if (**argv != '-') {
 211:             xerror("Bad option string \"%s\"", *argv);
 212:         }
 213:         while (*++*argv != '\0') {
 214:             for (optpt = options; optpt->optlet != '\0'; ++optpt) {
 215:                 if (optpt->optlet == **argv)
 216:                     goto found;
 217:             }
 218:             /* unknown option letter */
 219: usage:
 220:             fprintf(stderr, "usage: inews -t title");
 221:             fprintf(stderr, " [ -n newsgroups ]");
 222:             fprintf(stderr, " [ -e expiration date ]\n");
 223:             fprintf(stderr, "\t[ -f sender]\n\n");
 224:             xxit(1);
 225: 
 226:             found:;
 227:             if (optpt->flag == TRUE || (mode != UNKNOWN &&
 228:                 (mode&optpt->oldmode) == 0)) {
 229:                 xerror("Bad %c option", **argv);
 230:             }
 231:             if (mode == UNKNOWN)
 232:                 mode = optpt->newmode;
 233:             filchar = optpt->filchar;
 234:             optpt->flag = TRUE;
 235:             state = STRING;
 236:             ptr = optpt->buf;
 237:             len = BUFLEN;
 238:         }
 239: 
 240:         argv++;     /* done with this option arg. */
 241: 
 242:         } else {
 243: 
 244:         /*
 245: 		 * Pick up a piece of a string and put it into
 246: 		 * the appropriate buffer.
 247: 		 */
 248:         if (**argv == '-') {
 249:             state = OPTION;
 250:             argc++; /* uncount this arg. */
 251:             continue;
 252:         }
 253: 
 254:         if ((tlen = strlen(*argv)) >= len)
 255:             xerror("Argument string too long");
 256:         (void) strcpy(ptr, *argv++);
 257:         ptr += tlen;
 258:         if (*(ptr-1) != filchar)
 259:             *ptr++ = filchar;
 260:         len -= tlen + 1;
 261:         *ptr = '\0';
 262:         }
 263:     }
 264: 
 265:     /*
 266: 	 * ALL of the command line has now been processed. (!)
 267: 	 */
 268: 
 269:     tty = isatty(fileno(stdin));
 270: 
 271:     /* This code is really intended to be replaced by the control message. */
 272:     if (mode == CANCEL) {
 273:         char *p; FILE *f;
 274:         f = xfopen(filename, "r");
 275:         (void) hread(&header, f, TRUE);
 276:         p = index(header.path, ' ');
 277:         if (p != NULL)
 278:             *p = 0;
 279:         p = header.path;
 280:         if (strncmp(username, p, strlen(username))
 281:             && uid != ROOTID && uid != geteuid() && uid)
 282:             xerror("Not contributor");
 283:         cancel();
 284:         xxit(0);
 285:     }
 286: 
 287:     if (*header.nbuf) {
 288:         lcase(header.nbuf);
 289:         ptr = index(header.nbuf, '\0');
 290:         if (ptr[-1] == NGDELIM)
 291:             *--ptr = '\0';
 292:     }
 293:     (void) nstrip(header.title);
 294:     (void) nstrip(header.expdate);
 295:     (void) nstrip(header.followid);
 296:     if (mode != PROC) {
 297:         getident(&header);
 298:         if (hflag) {
 299:             header.path[0] = '\0';
 300:             (void) hread(&header, stdin, FALSE);
 301:             /* there are certain fields we won't let him specify. */
 302:             if (header.from[0])
 303:                 (void) strcpy(forgedname, header.from);
 304:             if (!header.approved[0])
 305:                 Mflag = FALSE;
 306:             header.from[0] = '\0';
 307:             header.subdate[0] = '\0';
 308:             header.sender[0] = '\0';
 309:         }
 310: #ifdef MYORG
 311:         if (header.organization[0] == '\0' && !Mflag) {
 312:             strncpy(header.organization, MYORG, BUFLEN);
 313:             if (strncmp(header.organization, "Frobozz", 7) == 0)
 314:                 header.organization[0] = '\0';
 315:             if (ptr = getenv("ORGANIZATION"))
 316:                 strncpy(header.organization, ptr, BUFLEN);
 317:             /*
 318: 			 * Note that the organization can also be turned off by
 319: 			 * setting it to the null string, either in MYORG or
 320: 			 * $ORGANIZATION in the environment.
 321: 			 */
 322:             if (header.organization[0] == '/') {
 323:                 mfd = fopen(header.organization, "r");
 324:                 if (mfd) {
 325:                     (void) fgets(header.organization, sizeof header.organization, mfd);
 326:                     (void) fclose(mfd);
 327:                 } else {
 328:                     header.organization[0] = '\0';
 329:                     logerr("Couldn't open %s",
 330:                         header.organization);
 331:                 }
 332:                 ptr = index(header.organization, '\n');
 333:                 if (ptr)
 334:                     *ptr = '\0';
 335:             }
 336:         }
 337: #endif /* MYORG */
 338:         if (forgedname[0]) {
 339:             register char *p1;
 340:             if (Mflag)
 341:                 sprintf(header.path, "%s!%s",
 342:                     FULLSYSNAME, username);
 343:             else if (!header.path[0]) {
 344:                 (void) strcpy(header.path, forgedname);
 345: 
 346:                 if ((p1 = strpbrk(header.path, "@ (<")) != NULL)
 347:                     *p1 = '\0';
 348:             }
 349:             if (!Mflag && !strpbrk(forgedname, "@ (<"))
 350:                 (void) sprintf(header.from,"%s@%s%s",
 351:                     forgedname, FULLSYSNAME, MYDOMAIN);
 352:             else
 353:                 (void) strncpy(header.from, forgedname, BUFLEN);
 354: 
 355:             (void) sprintf(header.sender, "%s@%s%s",
 356:                 username, FULLSYSNAME, MYDOMAIN);
 357:         } else {
 358:             gensender(&header, username);
 359:         }
 360:     }
 361: 
 362:     /* Authorize newsgroups. */
 363:     if (mode == PROC) {
 364: #ifdef BATCH
 365:         checkbatch();
 366: #endif /* BATCH */
 367:         (void) signal(SIGHUP, SIG_IGN);
 368:         (void) signal(SIGINT, SIG_IGN);
 369:         (void) signal(SIGQUIT, SIG_IGN);
 370:         header.ident[0] = '\0';
 371:         if (hread(&header, stdin, TRUE) == NULL)
 372:             xerror("Inbound news is garbled");
 373:         input();
 374:         if (history(&header)) {
 375:             log("Duplicate article %s rejected. Path: %s",
 376:                 header.ident, header.path);
 377:             xxit(0);
 378:         }
 379:     }
 380: 
 381:     /* Easy way to make control messages, since all.all.ctl is unblessed */
 382:     if (mode != PROC && prefix(header.title, "cmsg ") && header.ctlmsg[0] == 0)
 383:         (void) strcpy(header.ctlmsg, &header.title[5]);
 384:     is_ctl = mode != CREATENG &&
 385:         (ngmatch(header.nbuf, "all.all.ctl,") || header.ctlmsg[0]);
 386: #ifdef DEBUG
 387:     fprintf(stderr,"is_ctl set to %d\n", is_ctl);
 388: #endif
 389: 
 390:             /* Must end in comma (NGDELIM) */
 391: #define MODGROUPS   "mod.all,all.mod,all.announce,"
 392:     if (ngmatch(header.nbuf, MODGROUPS) && !header.approved[0]) {
 393:         mfd = mailhdr(&header, "Moderated newsgroup");
 394:         if (mfd) {
 395:             fprintf(mfd, "This newsgroup is moderated, and cannot be posted to directly.\n");
 396:             fprintf(mfd, "Please mail your article to the moderator for posting.\n");
 397:             hwrite(&header, mfd);
 398:             if (infp)
 399:                 while ((i = getc(infp)) != EOF)
 400:                     putc(i, mfd);
 401:             (void) mclose(mfd);
 402:         }
 403:         xerror("Unapproved moderated newsgroup.");
 404:     }
 405: 
 406:     if (mode != CREATENG) {
 407:         if (!*header.title)
 408:             xerror("No title, ng %s from %s", header.nbuf,
 409:                 header.from);
 410:         if (!*header.nbuf)
 411:             (void) strcpy(header.nbuf, DFLTNG);
 412:     }
 413: 
 414:     if (mode <= UNPROC) {
 415: #ifdef FASCIST
 416:         if (uid && uid != ROOTID && fascist(user, header.nbuf))
 417:                 xerror("User %s is not authorized to post to newsgroup %s", user, header.nbuf);
 418: #endif /* FASCIST */
 419:         ctlcheck();
 420:     }
 421: 
 422:     if (mode == CREATENG)
 423:         createng();
 424:     /* Determine input. */
 425:     if (mode != PROC)
 426:         input();
 427: 
 428:     /* Do the actual insertion. */
 429:     insert();
 430: }
 431: 
 432: /*
 433:  *	Create a newsgroup
 434:  */
 435: createng()
 436: {
 437: 
 438:     /*
 439: 	 * Only certain users are allowed to create newsgroups
 440: 	 */
 441:     if (uid != ROOTID && uid != geteuid() && uid) {
 442:         fprintf(stderr, "Please contact one of the local netnews people\n\tto create this group for you");
 443:         xxit(1);
 444:     }
 445: 
 446:     (void) sprintf(bfr, "%s/inews -n %s.ctl -t cmsg newgroup %s -d local",
 447:         LIB, header.nbuf, header.nbuf);
 448:     printf("Please type in a paragraph describing the new newsgroup.\n");
 449:     printf("End with control D as usual.\n");
 450:     printf("%s\n", bfr);
 451:     (void) fflush(stdout);
 452:     (void) system(bfr);
 453:     exit(0);
 454:     /*NOTREACHED*/
 455: }
 456: 
 457: char firstbufname[BUFLEN];
 458: /*
 459:  *	Link ARTICLE into dir for ngname and update active file.
 460:  */
 461: long
 462: localize(ngname)
 463: char    *ngname;
 464: {
 465:     char afline[BUFLEN];
 466:     long ngsize;
 467:     long fpos;
 468:     int e;
 469:     char *cp;
 470: 
 471:     lock();
 472:     actfp = xfopen(ACTIVE, "r+");
 473: 
 474:     for(;;) {
 475:         fpos = ftell(actfp);
 476:         if (fgets(afline, sizeof afline, actfp) == NULL) {
 477:             unlock();
 478:             (void) fclose(actfp);
 479:             logerr("Can't fine \"%s\" in active file", ngname);
 480:             return FALSE;       /* No such newsgroup locally */
 481:         }
 482:         if (prefix(afline, ngname)) {
 483:             (void) sscanf(afline, "%s %ld", bfr, &ngsize);
 484:             if (strcmp(bfr, ngname) == 0) {
 485:                 if (ngsize < 0 || ngsize > 99998) {
 486:                     logerr("found bad ngsize %ld ng %s, setting to 1", ngsize, bfr);
 487:                     ngsize = 1;
 488:                 }
 489:                 break;
 490:             }
 491:         }
 492:     }
 493:     for (;;) {
 494:         cp = dirname(ngname);
 495:         if (!exists(cp))
 496:             mknewsg(cp, ngname);
 497: 
 498:         (void) sprintf(bfr, "%s/%ld", cp, ngsize+1);
 499: #ifdef VMS
 500:         if (vmslink(ARTICLE, bfr) == 0)
 501:             break;
 502: #else /* !VMS */
 503:         if (link(ARTICLE, bfr) == 0)
 504:             break;
 505: #endif /* !VMS */
 506:         e = errno;  /* keep log from clobbering it */
 507:         log("Cannot install article as %s: %s", bfr, errmsg(errno));
 508:         if (e != EEXIST) {
 509:             logerr("Link into %s failed (%s); check dir permissions.",
 510:                 bfr, errmsg(e));
 511:             unlock();
 512:             (void) fclose(actfp);
 513:             return FALSE;
 514:         }
 515:         ngsize++;
 516:     }
 517: 
 518:     (void) fflush(actfp);
 519: #ifdef VMS
 520:     (void) fclose(actfp);
 521:     vmstounix(ACTIVE);
 522:     actfp = fopen(ACTIVE, "r+");
 523: #endif /* VMS */
 524: 
 525:     /*
 526: 	 * This works around a bug in the 4.1bsd stdio
 527: 	 * on fseeks to non even offsets in r+w files
 528: 	 */
 529:     if (fpos&1)
 530:         (void) rewind(actfp);
 531: 
 532:     (void) fseek(actfp, fpos, 0);
 533:     /* Has to be same size as old because of %05d.
 534: 	 * This will overflow with 99999 articles.
 535: 	 */
 536:     fprintf(actfp, "%s %05ld", ngname, ngsize+1);
 537:     if (ferror(actfp))
 538:         xerror("Active file write failed");
 539:     (void) fclose(actfp);
 540: #ifdef VMS
 541:     unixtovms(ACTIVE);
 542: #endif /* VMS */
 543:     unlock();
 544:     if (firstbufname[0] == '\0')
 545:         (void) strcpy(firstbufname, bfr);
 546:     (void) sprintf(bfr, "%s/%ld ", ngname, ngsize+1);
 547:     addhist(bfr);
 548:     return ngsize+1;
 549: }
 550: 
 551: /*
 552:  *	Localize for each newsgroup and broadcast.
 553:  */
 554: insert()
 555: {
 556:     register char *ptr;
 557:     register FILE *tfp;
 558:     register int c;
 559:     struct srec srec;   /* struct for sys file lookup	*/
 560:     struct tm *tm;
 561:     int is_invalid = FALSE;
 562:     int exitcode = 0;
 563:     long now;
 564: #ifdef DOXREFS
 565:     register char *nextref = header.xref;
 566: #endif /* DOXREFS */
 567: 
 568:     /* Fill up the rest of header. */
 569:     if (mode != PROC) {
 570:         history(&header);
 571:     }
 572:     dates(&header);
 573:     (void) time(&now);
 574:     tm = localtime(&now);
 575:     if (header.expdate[0])
 576:         addhist(" ");
 577: #ifdef USG
 578:     sprintf(bfr,"%2.2d/%2.2d/%d %2.2d:%2.2d\t",
 579: #else /* !USG */
 580:     sprintf(bfr,"%02d/%02d/%d %02d:%02d\t",
 581: #endif /* !USG */
 582:         tm->tm_mon+1, tm->tm_mday, tm->tm_year,tm->tm_hour, tm->tm_min);
 583:     addhist(bfr);
 584:     log("%s %s ng %s subj '%s' from %s",
 585:         mode==PROC ? "received" : "posted",
 586:         header.ident, header.nbuf, header.title, header.from);
 587: 
 588:     /* Clean up Newsgroups: line */
 589:     if (!is_ctl && mode != CREATENG)
 590:         is_invalid = ngfcheck(mode == PROC);
 591: 
 592:     /* Write article to temp file. */
 593:     tfp = xfopen(mktemp(ARTICLE), "w");
 594: 
 595:     if (is_invalid) {
 596:         logerr("No valid newsgroups found, moved to junk");
 597:         if (localize("junk"))
 598:             savehist(histline);
 599:         exitcode = 1;
 600:         goto writeout;
 601:     }
 602: 
 603:     if (time((time_t *)0) > (cgtdate(header.subdate) + HISTEXP) ){
 604:         logerr("Article too old, moved to junk");
 605:         if (localize("junk"))
 606:             savehist(histline);
 607:         exitcode = 1;
 608:         goto writeout;
 609:     }
 610: 
 611:     if (is_ctl) {
 612:         exitcode = control(&header);
 613:         if (localize("control") && exitcode != 0)
 614:             savehist(histline);
 615:     } else {
 616:         if (s_find(&srec, FULLSYSNAME) == FALSE) {
 617:             logerr("Cannot find my name '%s' in %s", FULLSYSNAME, SUBFILE);
 618:             srec = dummy_srec;
 619:         }
 620: #ifdef DOXREFS
 621:         (void) strncpy(nextref, FULLSYSNAME, BUFLEN);
 622: #endif /* DOXREFS */
 623:         for (ptr = nbuf; *ptr;) {
 624:             if (ngmatch(ptr,srec.s_nbuf) || index(ptr,'.') == NULL){
 625: #ifdef DOXREFS
 626:                 while (*nextref++)
 627:                     ;
 628:                 (void) sprintf(--nextref, " %s:%ld", ptr, localize(ptr));
 629: #else /* !DOXREFS */
 630:                 (void) localize(ptr);
 631: #endif /* !DOXREFS */
 632:             }
 633:             while (*ptr++)
 634:                 ;
 635:         }
 636:         if (firstbufname[0] == '\0') {
 637:             logerr("Newsgroups in active, but not sys");
 638:             (void) localize("junk");
 639:         }
 640:     }
 641: #ifdef DOXREFS
 642:     if (index(header.nbuf, NGDELIM) == NULL)
 643:         header.xref[0] = '\0';
 644: #endif /* DOXREFS */
 645: 
 646: writeout:
 647:     /* Part 1 of kludge to get around article truncation problem */
 648:     if ( (c=getc(infp)) != EOF) {
 649:         ungetc(c, infp);
 650:         if (c == ' ' || c == '\t') {
 651:             header.intnumlines++;
 652:             (void) sprintf(header.numlines, "%d",
 653:                 header.intnumlines);
 654:         }
 655:     }
 656:     /* End of part 1 */
 657:     lhwrite(&header, tfp);
 658:     if ((c = getc(infp)) != EOF) {
 659:         /* Part 2 of kludge to get around article truncation problem */
 660:         if (c == ' ' || c == '\t' )
 661:             putc('\n', tfp);
 662:         /* End of part 2 */
 663:         ungetc(c, infp);
 664:         while (fgets(bfr, BUFLEN, infp) != NULL)
 665:             fputs(bfr, tfp);
 666:         if (bfr[strlen(bfr)-1] != '\n')
 667:             putc('\n',tfp);
 668:     }
 669:     if (ferror(tfp))
 670:         xerror("Write failed for temp file");
 671:     (void) fclose(tfp);
 672:     (void) fclose(infp);
 673: 
 674:     if(exitcode == 0) {
 675:         int pid;
 676:         /* article has passed all the checks, so work in background */
 677:         if (mode != PROC)
 678:             if ((pid=fork()) < 0)
 679:                 xerror("Can't fork");
 680:             else if (pid > 0)
 681:                 exit(0);
 682: #ifdef SIGTTOU
 683:         signal(SIGTTOU, SIG_IGN);
 684: #endif /* SIGTTOU */
 685:         savehist(histline);
 686:         broadcast();
 687:     }
 688:     xxit(mode == PROC ? 0 : exitcode);
 689: }
 690: 
 691: input()
 692: {
 693:     register char *cp;
 694:     register int c;
 695:     register int empty = TRUE;
 696:     FILE *tmpfp;
 697:     int consec_newlines = 0;
 698:     int linecount = 0;
 699:     int linserted = 0;
 700: 
 701:     tmpfp = xfopen(mktemp(INFILE), "w");
 702:     if (*filename) {
 703:         tty = FALSE;
 704:         infp = xfopen(filename, "r");
 705:     } else {
 706:         infp = stdin;
 707:     }
 708:     while (!SigTrap && fgets(bfr, BUFLEN, stdin) != NULL) {
 709:         if (mode == PROC) { /* zap trailing empty lines */
 710: #ifdef ZAPNOTES
 711:             if (empty && bfr[0] == '#' && bfr[2] == ':'
 712:                 && header.nf_id[0] == '\0'
 713:                 && header.nf_from[0] == '\0' ) {
 714:                 (void) strcpy(header.nf_id, bfr);
 715:                 (void) nstrip(header.nf_id);
 716:                 (void) fgets(bfr, BUFLEN, stdin);
 717:                 (void) strcpy(header.nf_from, bfr);
 718:                 (void) nstrip(header.nf_from);
 719:                 (void) fgets(bfr, BUFLEN, stdin);
 720: 
 721:                 if (header.numlines[0]) {
 722:                     header.intnumlines -= 2;
 723:                     (void) sprintf(header.numlines, "%d", header.intnumlines);
 724:                 }
 725: 
 726:                 /* Strip trailing " - (nf)" */
 727:                 if ((cp = rindex(header.title, '-')) != NULL
 728:                     && !strcmp(--cp, " - (nf)"))
 729:                     *cp = '\0';
 730:                 log("Stripped notes header on %s", header.ident);
 731:                 continue;
 732:             }
 733: #endif /* ZAPNOTES */
 734:             if (bfr[0] == '\n' ||
 735:                 /* Bandage for older versions of inews */
 736:                 bfr[1] == '\n' && !isascii(bfr[0])) {
 737:                 consec_newlines++;  /* count it, in case */
 738:                 continue;       /* but don't write it*/
 739:             }
 740:             /* foo! a non-empty line. write out all saved lines. */
 741:             while (consec_newlines > 0) {
 742:                 putc('\n', tmpfp);
 743:                 consec_newlines--;
 744:                 linecount++;
 745:             }
 746:         }
 747:         if (mode != PROC && tty && strcmp(bfr, ".\n") == 0)
 748:             break;
 749:         for (cp = bfr; c = toascii(*cp); cp++) {
 750:             if (isprint(c) || isspace(c) || c == '\b')
 751:                 putc(c, tmpfp);
 752:             if (c == '\n')
 753:                 linecount++;
 754:         }
 755:         if (bfr[0] == '>')
 756:             linserted++;
 757:         empty = FALSE;
 758:     }
 759:     if (*filename)
 760:         (void) fclose(infp);
 761:     if (mode != PROC && linserted > (linecount-linserted))
 762:         xerror("Article rejected: More included text than new text");
 763: 
 764:     if (mode != PROC && !is_ctl && header.sender[0] == '\0') {
 765:         int siglines = 0;
 766:         char sbuf[BUFLEN];
 767:         (void) sprintf(bfr, "%s/%s", userhome, ".signature");
 768:         if (access(bfr, 4) == 0) {
 769:             if ((infp = fopen(bfr, "r")) == NULL) {
 770:                 (void) fprintf(stderr,
 771:     "inews: \"%s\" left off (must be readable by \"inews\" owner)\n", bfr);
 772:                 goto finish;
 773:             }
 774: 
 775:             while (fgets(sbuf, sizeof sbuf, infp) != NULL)
 776:                 if (++siglines > 4)
 777:                     break;
 778:             if (siglines > 4)
 779:                 fprintf(stderr,".signature not included (> 4 lines)\n");
 780:             else {
 781:                 rewind(infp);
 782:                 fprintf(tmpfp, "-- \n");    /* To separate */
 783:                 linecount++;
 784:                 while ((c = getc(infp)) != EOF) {
 785:                     putc(c, tmpfp);
 786:                     if (c == '\n')
 787:                         linecount++;
 788:                 }
 789:             }
 790:             (void) fclose(infp);
 791:         }
 792:     }
 793: 
 794: finish:
 795:     if (ferror(tmpfp))
 796:         xerror("write failed to temp file");
 797:     (void) fclose(tmpfp);
 798:     if (SigTrap) {
 799:         if (tty)
 800:             fprintf(stderr, "Interrupt\n");
 801:         if (tty && !empty)
 802:             fwait(fsubr(newssave, (char *) NULL, (char *) NULL));
 803:         if (!tty)
 804:             log("Blown away by an interrupt %d", SigTrap);
 805:         xxit(1);
 806:     }
 807:     if (tty)
 808:         fprintf(stderr, "EOT\n");
 809:     fflush(stdout);
 810:     infp = fopen(INFILE, "r");
 811:     if (header.numlines[0]) {
 812:         /*
 813: 		 * Check line count if there's already one attached to
 814: 		 * the article.  Could make this a fatal error -
 815: 		 * throwing it away if it got chopped, in hopes that
 816: 		 * another copy will come in later with a correct
 817: 		 * line count.  But that seems a bit much for now.
 818: 		 */
 819:         if (linecount != header.intnumlines) {
 820:             if (linecount == 0)
 821:                 xerror("%s rejected. linecount expected %d, got 0", header.ident, header.intnumlines);
 822:             if (linecount > header.intnumlines ||
 823:                 linecount+consec_newlines < header.intnumlines)
 824:                 log("linecount expected %d, got %d", header.intnumlines, linecount+consec_newlines);
 825:         }
 826:         /* adjust count for blank lines we stripped off */
 827:         if (consec_newlines) {
 828:             header.intnumlines -= consec_newlines;
 829:             if (header.intnumlines < 0 )
 830:                 header.intnumlines = 0; /* paranoia */
 831:             (void) sprintf(header.numlines, "%d", header.intnumlines);
 832:         }
 833: 
 834:     } else {
 835:         /* Attach a line count to the article. */
 836:         header.intnumlines = linecount;
 837:         (void) sprintf(header.numlines, "%d", linecount);
 838:     }
 839: }
 840: 
 841: /*
 842:  * Make the directory for a new newsgroup.  ngname should be the
 843:  * full pathname of the directory.  Do the other stuff too.
 844:  * The various games with setuid and chown are to try to make sure
 845:  * the directory is owned by NEWSUSR and NEWSGRP, which is tough to
 846:  * do if you aren't root.  This will work on a UCB system (which allows
 847:  * setuid(geteuid()) or a USG system (which allows you to give away files
 848:  * you own with chown), otherwise you have to change your kernel to allow
 849:  * one of these things or run with your dirs 777 so that it doesn't matter
 850:  * who owns them.
 851:  */
 852: mknewsg(fulldir, ngname)
 853: char    *fulldir;
 854: char    *ngname;
 855: {
 856: #ifdef USG
 857:     register char *p;
 858:     char parent[200];
 859:     char sysbuf[200];
 860:     struct stat sbuf;
 861: #endif /* USG */
 862: 
 863:     if (ngname == NULL || !isalpha(ngname[0]))
 864:         xerror("Tried to make illegal newsgroup %s", ngname);
 865: 
 866: #ifdef USG
 867:     /*
 868: 	 * If the parent is 755 the setuid(getuid)
 869: 	 * will fail, and since mkdir is suid, and our real uid is random,
 870: 	 * the mkdir will fail.  So we have to temporarily chmod it to 777.
 871: 	 */
 872:     (void) strcpy(parent, fulldir);
 873:     while (p = rindex(parent, '/')) {
 874:         *p = '\0';
 875:         if (stat(parent, &sbuf) == 0) {
 876:             (void) chmod(parent, 0777);
 877:             break;
 878:         }
 879:     }
 880: #endif /* USG */
 881: 
 882:     /* Create the directory */
 883:     mkparents(fulldir);
 884:     if (mkdir(fulldir, 0777) < 0)
 885:         xerror("Cannot mkdir %s: %s", fulldir, errmsg(errno));
 886: 
 887: #ifdef USG
 888:     (void) chmod(parent, (int)sbuf.st_mode);    /* put it back */
 889:     /*
 890: 	 * Give away the directories we just created which were assigned
 891: 	 * our real uid.
 892: 	 */
 893:     (void) setuid(uid);
 894:     (void) chown(fulldir, duid, dgid);
 895:     (void) strcpy(sysbuf, fulldir);
 896:     while (p = rindex(sysbuf, '/')) {
 897:         *p = '\0';
 898:         /* stop when get to last known good parent */
 899:         if (strcmp(sysbuf, parent) == 0)
 900:             break;
 901:         (void) chown(sysbuf, duid, dgid);
 902:     }
 903:     (void) setuid(duid);
 904: #endif /* USG */
 905: 
 906:     log("make newsgroup %s in dir %s", ngname, fulldir);
 907: }
 908: 
 909: /*
 910:  * If any parent directories of this dir don't exist, create them.
 911:  */
 912: mkparents(dname)
 913: char *dname;
 914: {
 915:     char buf[200];
 916:     register char *p;
 917: 
 918:     (void) strcpy(buf, dname);
 919:     p = rindex(buf, '/');
 920:     if (p)
 921:         *p = '\0';
 922:     if (exists(buf))
 923:         return;
 924:     mkparents(buf);
 925:     if (mkdir(buf, 0777) < 0)
 926:         xerror("Can not mkdir %s: %s", buf, errmsg(errno));
 927: }
 928: 
 929: cancel()
 930: {
 931:     register FILE *fp;
 932: 
 933:     log("cancel article %s", filename);
 934:     fp = fopen(filename, "r");
 935:     if (fp == NULL) {
 936:         log("article %s not found", filename);
 937:         return;
 938:     }
 939:     if (hread(&header, fp, TRUE) == NULL)
 940:         xerror("Article is garbled.");
 941:     (void) fclose(fp);
 942:     (void) unlink(filename);
 943: }

Defined functions

cancel defined in line 929; used 1 times
createng defined in line 435; used 1 times
input defined in line 691; used 2 times
insert defined in line 554; used 1 times
localize defined in line 461; used 7 times
main defined in line 85; never used
mknewsg defined in line 852; used 1 times
mkparents defined in line 912; used 2 times

Defined variables

Progname defined in line 42; never used
SccsId defined in line 20; never used
dummy_srec defined in line 40; used 1 times
firstbufname defined in line 457; used 3 times
forgedname defined in line 37; used 7 times

Defined macros

CANCEL defined in line 34; used 2 times
CREATENG defined in line 35; used 5 times
MODGROUPS defined in line 391; used 1 times
Mflag defined in line 66; used 4 times
OPTION defined in line 28; used 3 times
PROC defined in line 33; used 16 times
STRING defined in line 29; used 1 times
UNKNOWN defined in line 31; used 16 times
UNPROC defined in line 32; used 11 times
hflag defined in line 62; used 1 times
oflag defined in line 64; never used
Last modified: 1986-03-20
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2757
Valid CSS Valid XHTML 1.0 Strict