sources-request@mirror.UUCP (11/06/86)
Submitted by: seismo!rick (Rick Adams) Mod.sources: Volume 7, Issue 53 Archive-name: 2.11news/Part13 # To extract, sh this file # # news 2.11 source part 3 of 9 # if test ! -d src then mkdir src fi echo x - src/inews.c 1>&2 sed 's/.//' >src/inews.c <<'*-*-END-of-src/inews.c-*-*' -/* - * This software is Copyright (c) 1986 by Rick Adams. - * - * Permission is hereby granted to copy, reproduce, redistribute or - * otherwise use this software as long as: there is no monetary - * profit gained specifically from the use or reproduction or this - * software, it is not sold, rented, traded or otherwise marketed, and - * this copyright notice is included prominently in any copy - * made. - * - * The author make no claims as to the fitness or correctness of - * this software for any use whatsoever, and it is provided as is. - * Any use of this software is at the user's own risk. - * - * inews - insert, receive, and transmit news articles. - * - */ - -#ifdef SCCSID -static char *SccsId = "@(#)inews.c 2.69 10/30/86"; -#endif /* SCCSID */ - -#include "iparams.h" -#include <errno.h> - -#ifdef BSD4_2 -# include <sys/dir.h> -# include <sys/file.h> -#else /* !BSD4_2 */ -# include "ndir.h" -# ifdef USG -# include <fcntl.h> -# endif /* USG */ -# ifdef LOCKF -# include <unistd.h> -# endif /* LOCKF */ -#endif /* !BSD4_2 */ -/* local defines for inews */ - -#define OPTION 0 /* pick up an option string */ -#define STRING 1 /* pick up a string of arguments */ - -#define UNKNOWN 0001 /* possible modes for news program */ -#define UNPROC 0002 /* Unprocessed input */ -#define PROC 0004 /* Processed input */ -#define CONTROL 0010 /* Control Message */ -#define CREATENG 0020 /* Create a new newsgroup */ - -char forgedname[NAMELEN]; /* A user specified -f option. */ -int spool_news = FALSE; -extern char histline[]; -/* Fake sys line in case they forget their own system */ -struct srec dummy_srec = { "MEMEME", "", "all", "", "" }; - -char *Progname = "inews"; /* used by xerror to identify failing program */ - -struct { /* options table. */ - char optlet; /* option character. */ - char filchar; /* if to pickup string, fill character. */ - int flag; /* TRUE if have seen this opt. */ - int oldmode; /* OR of legal input modes. */ - int newmode; /* output mode. */ - char *buf; /* string buffer */ -} *optpt, options[] = { /* -optlet filchar flag oldmode newmode buf */ -'t', ' ', FALSE, UNPROC, UNKNOWN, header.title, -'n', NGDELIM, FALSE, UNPROC, UNKNOWN, header.nbuf, -'d', '\0', FALSE, UNPROC, UNKNOWN, header.distribution, -'e', ' ', FALSE, UNPROC, UNKNOWN, header.expdate, -'p', '\0', FALSE, UNKNOWN|PROC, PROC, filename, -'f', '\0', FALSE, UNPROC, UNKNOWN, forgedname, -'F', ' ', FALSE, UNPROC, UNKNOWN, header.followid, -'c', ' ', FALSE, UNKNOWN,UNKNOWN, header.ctlmsg, -'C', ' ', FALSE, UNKNOWN,CREATENG, header.ctlmsg, -#define hflag options[9].flag -'h', '\0', FALSE, UNPROC, UNKNOWN, filename, -#define oflag options[10].flag -'o', '\0', FALSE, UNPROC, UNKNOWN, header.organization, -#define Mflag options[11].flag -'M', '\0', FALSE, UNPROC, UNKNOWN, filename, -'a', '\0', FALSE, UNPROC, UNKNOWN, header.approved, -'U', '\0', FALSE, PROC, PROC, filename, -'S', '\0', FALSE, UNKNOWN|PROC, UNPROC, filename, -'x', '\0', FALSE, UNPROC, UNKNOWN, not_here, -'r', '\0', FALSE, UNPROC, UNKNOWN, header.replyto, -'\0', '\0', 0, 0, 0, (char *)NULL -}; - -FILE *mailhdr(); -extern int errno; - -struct timeb Now; - -/* - * Authors: - * Matt Glickman glickman@ucbarpa.Berkeley.ARPA - * Mark Horton mark@cbosgd.UUCP - * Stephen Daniels swd@mcnc.UUCP - * Tom Truscott trt@duke.UUCP - * Rick Adams rick@seismo.CSS.GOV - * IHCC version adapted by: - * Larry Marek larry@ihuxf.UUCP - */ -main(argc, argv) -int argc; -register char **argv; -{ - int state; /* which type of argument to pick up */ - int tlen, len; /* temps for string processing routine */ - register char *ptr; /* pointer to rest of buffer */ - int filchar; /* fill character (state = STRING) */ - char *user = NULL, *home = NULL; /* environment temps */ - struct passwd *pw; /* struct for pw lookup */ - struct group *gp; /* struct for group lookup */ - register int i; - FILE *mfd; /* mail file file-descriptor */ - char cbuf[BUFLEN]; /* command buffer */ - - /* uuxqt doesn't close all it's files */ - for (i = 3; !close(i); i++) - ; - /* set up defaults and initialize. */ - mode = UNKNOWN; - infp = stdin; - pathinit(); - ptr = rindex(*argv, '/'); - if (!ptr) - ptr = *argv - 1; - actfp = xfopen(ACTIVE, "r+"); -#ifdef BSD4_2 - if (flock(fileno(actfp), LOCK_SH|LOCK_NB) < 0 && errno == EWOULDBLOCK) -#else /* !BSD4_2 */ -#ifdef LOCKF - if (lockf(fileno(actfp), F_TLOCK, 0) < 0 && errno == EAGAIN) -#else /* !LOCKF */ - sprintf(bfr, "%s.lock", ACTIVE); - if (LINK(ACTIVE,bfr) < 0 && errno == EEXIST) -#endif /* V7 */ -#endif /* !BSD4_2 */ - spool_news = TRUE; - else { -#ifdef SPOOLNEWS - if (argc > 1 && !strcmp(*(argv+1), "-S")) { - argc--; - argv++; - } else - spool_news = TRUE; - -#endif /* SPOOLNEWS */ -#if !defined(BSD4_2) && !defined(LOCKF) - (void) UNLINK(bfr); -#endif /* !BSD4_2 && !LOCKF */ - } - if (argc > 1 && !strcmp(*(argv+1), "-U")) { - dounspool(); - /* NOT REACHED */ - } - - if (!strncmp(ptr+1, "rnews", 5)) { - mode = PROC; - if (spool_news) { - dospool((char *)NULL, FALSE); - /* NOT REACHED */ - } -#ifdef NICENESS - nice(NICENESS); -#endif /* NICENESS */ - } else - if (argc < 2) - goto usage; - - state = OPTION; - header.title[0] = header.nbuf[0] = filename[0] = '\0'; - - /* check for existence of special files */ - if (!rwaccess(ARTFILE)) { - mfd = mailhdr((struct hbuf *)NULL, exists(ARTFILE) ? "Unwritable files!" : "Missing files!"); - if (mfd != NULL) { -#ifdef HIDDENNET - fprintf(mfd,"System: %s.%s\n\nThere was a problem with %s!!\n", LOCALSYSNAME, FULLSYSNAME, ARTFILE); -#else /* !HIDDENNET */ - fprintf(mfd,"System: %s\n\nThere was a problem with %s!!\n", FULLSYSNAME, ARTFILE); -#endif /* !HIDDENNET */ - (void) sprintf(cbuf, "touch %s;chmod 666 %s", ARTFILE, ARTFILE); - (void) system(cbuf); - if (rwaccess(ARTFILE)) - fprintf(mfd, "The problem has been taken care of.\n"); - else - fprintf(mfd, "Corrective action failed - check suid bits.\n"); - (void) mclose(mfd); - } - } - if (!rwaccess(ACTIVE)) { - mfd = mailhdr((struct hbuf *)NULL, exists(ACTIVE) ? "Unwritable files!" : "Missing files!"); - if (mfd != NULL) { -#ifdef HIDDENNET - fprintf(mfd,"System: %s.%s\n\nThere was a problem with %s!!\n", LOCALSYSNAME, FULLSYSNAME, ARTFILE); -#else /* !HIDDENNET */ - fprintf(mfd, "System: %s\n\nThere was a problem with %s!!\n", FULLSYSNAME, ACTIVE); -#endif /* !HIDDENNET */ - (void) sprintf(cbuf, "touch %s;chmod 666 %s", ACTIVE, ACTIVE); - (void) system(cbuf); - if (rwaccess(ACTIVE)) - fprintf(mfd, "The problem has been taken care of.\n"); - else - fprintf(mfd, "Corrective action failed - check suid bits.\n"); - (void) mclose(mfd); - } - } - SigTrap = FALSE; /* true if a signal has been caught */ - if (mode != PROC) { - (void) signal(SIGHUP, onsig); - (void) signal(SIGINT, onsig); - } - savmask = umask(N_UMASK); /* set up mask */ - uid = getuid(); - gid = getgid(); - duid = geteuid(); - dgid = getegid(); - (void) ftime(&Now); - if (uid == 0 && duid == 0) { - /* - * Must go through with this kludge since - * some systems do not honor the setuid bit - * when root invokes a setuid program. - */ - if ((pw = getpwnam(NEWSUSR)) == NULL) - xerror("Cannot get NEWSU pw entry"); - - duid = pw->pw_uid; - if ((gp = getgrnam(NEWSGRP)) == NULL) - xerror("Cannot get NEWSG gr entry"); - dgid = gp->gr_gid; - (void) setgid(dgid); - (void) setuid(duid); - } - -#ifndef IHCC - /* - * We force the use of 'getuser()' to prevent forgery of articles - * by just changing $LOGNAME - */ - if (isatty(fileno(stderr))) { - if ((user = getenv("USER")) == NULL) - user = getenv("LOGNAME"); - if ((home = getenv("HOME")) == NULL) - home = getenv("LOGDIR"); - } -#endif - if (user == NULL || home == NULL) - getuser(); - else { - if (username == NULL || username[0] == 0) { - username = AllocCpy(user); - } - userhome = AllocCpy(home); - } - getuser(); - - /* loop once per arg. */ - - ++argv; /* skip first arg, which is prog name. */ - - while (--argc) { - if (state == OPTION) { - if (**argv != '-') { - xerror("Bad option string \"%s\"", *argv); - } - while (*++*argv != '\0') { - for (optpt = options; optpt->optlet != '\0'; ++optpt) { - if (optpt->optlet == **argv) - goto found; - } - /* unknown option letter */ -usage: - fprintf(stderr, "usage: inews -t title"); - fprintf(stderr, " [ -n newsgroups ]"); - fprintf(stderr, " [ -e expiration date ]\n"); - fprintf(stderr, "\t[ -f sender]\n\n"); - xxit(1); - - found:; - if (optpt->flag == TRUE || (mode != UNKNOWN && - (mode&optpt->oldmode) == 0)) { - xerror("Bad %c option", **argv); - } - if (mode == UNKNOWN) - mode = optpt->newmode; - filchar = optpt->filchar; - optpt->flag = TRUE; - state = STRING; - ptr = optpt->buf; - len = BUFLEN; - } - - argv++; /* done with this option arg. */ - - } else { - - /* - * Pick up a piece of a string and put it into - * the appropriate buffer. - */ - if (**argv == '-') { - state = OPTION; - argc++; /* uncount this arg. */ - continue; - } - - if ((tlen = strlen(*argv)) >= len) - xerror("Argument string too long"); - (void) strcpy(ptr, *argv++); - ptr += tlen; - if (*(ptr-1) != filchar) - *ptr++ = filchar; - len -= tlen + 1; - *ptr = '\0'; - } - } - - /* - * ALL of the command line has now been processed. (!) - */ - - if (*filename) { - (void) fclose(stdin); - infp = freopen(filename, "r", stdin); - if (infp == NULL) - xerror("freopen(%s): %s", filename, errmsg(errno)); - } else - infp = stdin; - - tty = isatty(fileno(infp)); - - if (mode == CREATENG) - createng(); - - if (header.ctlmsg[0] != '\0' && header.title[0] == '\0') - (void) strcpy(header.title, header.ctlmsg); - - if (*header.nbuf) { - lcase(header.nbuf); - ptr = index(header.nbuf, '\0'); - if (ptr[-1] == NGDELIM) - *--ptr = '\0'; - } - (void) nstrip(header.title); - (void) nstrip(header.expdate); - (void) nstrip(header.followid); - if (mode != PROC) { - if (hflag) { - header.path[0] = '\0'; - (void) hread(&header, infp, FALSE); - /* there are certain fields we won't let him specify. */ - if (header.from[0]) - (void) strcpy(forgedname, header.from); - if (!header.approved[0]) - Mflag = FALSE; - header.from[0] = '\0'; - header.sender[0] = '\0'; - if (header.subdate[0] && cgtdate(header.subdate) < 0) - header.subdate[0] = '\0'; - } - - if (header.ident[0] == '\0') - getident(&header); - - if (forgedname[0]) { - register char *p1; - if (Mflag) - sprintf(header.path, "%s!%s", - FULLSYSNAME, username); - else if (!header.path[0]) { - (void) strcpy(header.path, forgedname); - - if ((p1 = strpbrk(header.path, "@ (<")) != NULL) - *p1 = '\0'; - } - if (!Mflag && !strpbrk(forgedname, "@ (<")) - (void) sprintf(header.from,"%s@%s%s", - forgedname, FULLSYSNAME, MYDOMAIN); - else - (void) strncpy(header.from, forgedname, BUFLEN); - - (void) sprintf(header.sender, "%s@%s%s", - username, FULLSYSNAME, MYDOMAIN); - } else { - gensender(&header, username); - } -#ifdef MYORG - if (header.organization[0] == '\0' && !Mflag && - header.sender[0] == '\0') { - strncpy(header.organization, MYORG, BUFLEN); - if (strncmp(header.organization, "Frobozz", 7) == 0) - header.organization[0] = '\0'; - if (ptr = getenv("ORGANIZATION")) - strncpy(header.organization, ptr, BUFLEN); - /* - * Note that the organization can also be turned off by - * setting it to the null string, either in MYORG or - * $ORGANIZATION in the environment. - */ - if (header.organization[0] == '/') { - mfd = fopen(header.organization, "r"); - if (mfd) { - (void) fgets(header.organization, sizeof header.organization, mfd); - (void) fclose(mfd); - } else { - header.organization[0] = '\0'; - logerr("Couldn't open %s", - header.organization); - } - ptr = index(header.organization, '\n'); - if (ptr) - *ptr = '\0'; - } - } -#endif /* MYORG */ - } - - /* Authorize newsgroups. */ - if (mode == PROC) { -#ifdef BATCH - checkbatch(); -#endif /* BATCH */ - (void) signal(SIGHUP, SIG_IGN); - (void) signal(SIGINT, SIG_IGN); - (void) signal(SIGQUIT, SIG_IGN); - header.ident[0] = '\0'; - if (hread(&header, infp, TRUE) == NULL) - error("Inbound news is garbled"); - input(); - } - /* always check history */ - - if (history(&header)) { - log("Duplicate article %s rejected. Path: %s", - header.ident, header.path); - xxit(0); - } - - /* Easy way to make control messages, since all.all.ctl is unblessed */ - if (mode != PROC && prefix(header.title, "cmsg ") && header.ctlmsg[0] == 0) - (void) strcpy(header.ctlmsg, &header.title[5]); - is_ctl = mode != CREATENG && - (ngmatch(header.nbuf, "all.all.ctl,") || header.ctlmsg[0]); -#ifdef DEBUG - fprintf(stderr,"is_ctl set to %d\n", is_ctl); -#endif - - if (mode != CREATENG) { - if (!*header.title) - error("No title, ng %s from %s", header.nbuf, - header.from); - if (!*header.nbuf) - (void) strcpy(header.nbuf, DFLTNG); - } - - if (mode <= UNPROC) { -#ifdef FASCIST - if (uid && uid != ROOTID && fascist(user, header.nbuf)) - xerror("User %s is not authorized to post to newsgroup %s", - user, header.nbuf); -#endif /* FASCIST */ - ctlcheck(); - } - - if (mode == CREATENG) - createng(); - - /* Determine input. */ - if (mode != PROC) - input(); - if (header.intnumlines == 0 && !is_ctl) - error("%s rejected: no text lines", header.ident); - - dates(&header); - - /* Do the actual insertion. */ - insert(); -} - -dospool(batchcmd, dolhwrite) -char *batchcmd; -int dolhwrite; -{ - register int c; - register FILE *sp; - register struct tm *tp; - time_t t; - char buf[BUFLEN]; - extern struct tm *gmtime(); - - (void) time(&t); - tp = gmtime(&t); - /* This file name "has to" be unique (right?) */ -#ifdef USG - (void) sprintf(buf, "%s/.rnews/%2.2d%2.2d%2.2d%2.2d%2.2d%x", -#else -#ifdef VMS - /* Eunice doesn't like dots in directory names */ - (void) sprintf(buf, "%s/+rnews/%02d%02d%02d%02d%02d%x", -#else /* V7 */ - (void) sprintf(buf, "%s/.rnews/%02d%02d%02d%02d%02d%x", -#endif /* V7 */ -#endif /* VMS */ - SPOOLDIR, - tp->tm_year, tp->tm_mon+1, tp->tm_mday, - tp->tm_hour, tp->tm_min, getpid()); - sp = xfopen(buf, "w"); - if (batchcmd != NULL) - fprintf(sp, "%s\n", batchcmd); - if (dolhwrite) - lhwrite(&header, sp); - while ((c = getc(infp)) != EOF) - putc(c, sp); - fclose(sp); - xxit(0); - /* NOTREACHED */ -} - -/* - * Create a newsgroup - */ -createng() -{ - register char *cp; - - /* - * Only certain users are allowed to create newsgroups - */ - if (uid != ROOTID && uid != duid && uid) { - fprintf(stderr, "Please contact one of the local netnews people\n\tto create this group for you"); - xxit(1); - } - if (header.distribution[0] == '\0') -#ifdef ORGDISTRIB - strcpy(header.distribution, ORGDISTRIB); -#else /* !ORGDISTRIB */ - strcpy(header.distribution, "local"); -#endif /* !ORGDISTRIB */ - - (void) strcpy(header.nbuf, header.ctlmsg); - if ((cp=index(header.nbuf, ' ')) != NULL) - *cp = '\0'; - - if (header.approved[0] == '\0') - (void) sprintf(header.approved, "%s@%s%s", - username, FULLSYSNAME, MYDOMAIN); - (void) sprintf(bfr, "%s/inews -n %s.ctl -c newgroup %s -d %s -a \"%s\"", - LIB, header.nbuf, header.ctlmsg, header.distribution, - header.approved); - if (tty) { - printf("Please type in a paragraph describing the new newsgroup.\n"); - printf("End with control D as usual.\n"); - } - printf("%s\n", bfr); - (void) fflush(stdout); - (void) system(bfr); - exit(0); - /*NOTREACHED*/ -} - -char firstbufname[BUFLEN]; -/* - * Link ARTICLE into dir for ngname and update active file. - */ -long -localize(ngname) -char *ngname; -{ - char afline[BUFLEN]; - long ngsize; - long fpos; - int e; - char *cp; - - lock(); - (void) rewind(actfp); clearerr(actfp); - - for(;;) { - fpos = ftell(actfp); - if (fgets(afline, sizeof afline, actfp) == NULL) { - unlock(); - logerr("Can't find \"%s\" in active file", ngname); - return FALSE; /* No such newsgroup locally */ - } - if (prefix(afline, ngname)) { - (void) sscanf(afline, "%s %ld", bfr, &ngsize); - if (strcmp(bfr, ngname) == 0) { - if (ngsize < 0 || ngsize > 99998) { - logerr("found bad ngsize %ld ng %s, setting to 1", ngsize, bfr); - ngsize = 1; - } - break; - } - } - } - for (;;) { - cp = dirname(ngname); - - (void) sprintf(bfr, "%s/%ld", cp, ngsize+1); -#ifdef VMS - /* - * The effect of this code is to store the article in the first - * newsgroup's directory and to put symbolic links elsewhere. - * If this is the first group, firstbufname is not yet filled - * in. It should be portable to other link-less systems. - * epimass!jbuck - */ - if (firstbufname[0]) { - if (vmslink(firstbufname, bfr) == 0) - break; - } else if (rename(ARTICLE, bfr) == 0) - break; -#else /* !VMS */ - if (link(ARTICLE, bfr) == 0) - break; -#endif /* !VMS */ - if (!exists(cp)) - mknewsg(cp, ngname); -#ifdef VMS - if (firstbufname[0]) { - if (vmslink(firstbufname, bfr) == 0) - break; - } else if (rename(ARTICLE, bfr) == 0) - break; -#else /* !VMS */ - if (link(ARTICLE, bfr) == 0) - break; -#endif /* !VMS */ - e = errno; /* keep log from clobbering it */ - log("Cannot install article as %s: %s", bfr, errmsg(errno)); - if (e != EEXIST) { - logerr("Link into %s failed (%s); check dir permissions.", - bfr, errmsg(e)); - unlock(); - return FALSE; - } - ngsize++; - } - - /* - * This works around a bug in the 4.1bsd stdio - * on fseeks to non even offsets in r+w files - */ - if (fpos&1) - (void) rewind(actfp); - - (void) fseek(actfp, fpos, 0); -#ifdef USG - /* - * U G L Y K L U D G E - * This utter piece of tripe is the only way I know of to get - * around the fact that ATT BROKE standard IO in System 5.2. - * Basically, you can't open a file for "r+" and then try and - * write to it. This works on all "real" USGUnix systems, It will - * probably break on some obscure look alike that doesnt use the - * real ATT stdio.h - * Don't blame me, blame ATT. stdio should have already done the - * following line for us, but it doesn't - */ - actfp->_flag |= _IOWRT; -#endif /* USG */ - /* Has to be same size as old because of %05d. - * This will overflow with 99999 articles. - */ - fprintf(actfp, "%s %05ld", ngname, ngsize+1); - (void) fflush(actfp); - if (ferror(actfp)) - xerror("Active file write failed"); - unlock(); - if (firstbufname[0] == '\0') - (void) strcpy(firstbufname, bfr); - (void) sprintf(bfr, "%s/%ld ", ngname, ngsize+1); - addhist(bfr); - return ngsize+1; -} - -/* - * Localize for each newsgroup and broadcast. - */ -insert() -{ - register char *ptr; - register FILE *tfp; - register int c; - struct srec srec; /* struct for sys file lookup */ - struct tm *tm, *gmtime(); - int is_invalid = FALSE; - int exitcode = 0; - long now; -#ifdef DOXREFS - register char *nextref = header.xref; -#endif /* DOXREFS */ - - /* Clean up Newsgroups: line */ - if (!is_ctl && mode != CREATENG) - is_invalid = ngfcheck(mode == PROC); - - (void) time(&now); - tm = gmtime(&now); - if (header.expdate[0]) - addhist(" "); -#ifdef USG - sprintf(bfr,"%2.2d/%2.2d/%d %2.2d:%2.2d\t", -#else /* !USG */ - sprintf(bfr,"%02d/%02d/%d %02d:%02d\t", -#endif /* !USG */ - tm->tm_mon+1, tm->tm_mday, tm->tm_year,tm->tm_hour, tm->tm_min); - addhist(bfr); - log("%s %s ng %s subj '%s' from %s", - spool_news ? "queued" : (mode==PROC ? "received" : "posted"), - header.ident, header.nbuf, header.title, header.from); - - /* Write article to temp file. */ - tfp = xfopen(mktemp(ARTICLE), "w"); - - if (is_invalid) { - logerr("No valid newsgroups found, moved to junk"); - if (localize("junk")) - savehist(histline); - exitcode = 1; - goto writeout; - } - -#ifdef ZAPNOTES - if (strcmp(header.title, "Re: Orphaned Response") == 0) { - logerr("Orphaned Response, moved to junk"); - if (localize("junk")) - savehist(histline); - exitcode = 1; - goto writeout; - } -#endif /* ZAPNOTES */ - - if (time((time_t *)0) > (cgtdate(header.subdate) + HISTEXP) ){ - logerr("Article too old, moved to junk"); - if (localize("junk")) - savehist(histline); - exitcode = 1; - goto writeout; - } - - if (is_mod[0] != '\0' /* one of the groups is moderated */ - && header.approved[0] == '\0') { /* and unapproved */ - struct hbuf mhdr; - FILE *mfd; - register char *p; - char modadd[BUFLEN]; -#ifdef DONTFOWARD - if(mode == PROC) { - logerr("Unapproved article in moderated group %s", - is_mod); - if (localize("junk")) - savehist(histline); - goto writeout; - } -#endif /* DONTFORWARD */ - fprintf(stderr,"%s is moderated and may not be posted to", - is_mod); - fprintf(stderr," directly.\nYour article is being mailed to"); - fprintf(stderr," the moderator who will post it for you.\n"); - /* Let's find a path to the backbone */ - sprintf(bfr, "%s/mailpaths", LIBDIR); - mfd = xfopen(bfr, "r"); - do { - if (fgets(bfr, sizeof bfr, mfd) == NULL) - xerror("Can't find backbone in %s/mailpaths", - LIBDIR); - } while (!prefix(bfr, "backbone")); - if (sscanf(bfr, "%*s %s", modadd) != 1) - xerror("backbone address corrupted"); - /* fake a header for mailhdr */ - mhdr.from[0] = '\0'; - mhdr.replyto[0] = '\0'; - p = is_mod; - while (*++p) - if (*p == '.') - *p = '-'; - sprintf(bfr, "Submission for %s", is_mod); - sprintf(mhdr.path, modadd, is_mod); - mfd = mailhdr(&mhdr, bfr); - if (mfd == NULL) - xerror("Can't send mail to %s", mhdr.path); - lhwrite(&header, mfd); - while ((c = getc(infp)) != EOF) - putc(c, mfd); - mclose(mfd); - log("Article mailed to %s", mhdr.path); - xxit(0); - } - - if (spool_news && mode != PROC) { - fprintf(stderr,"Your article has been spooled for later processing.\n"); - dospool((char *)NULL, TRUE); - /* NOT REACHED */ - } - - if (is_ctl) { - exitcode = control(&header); - if (localize("control") && exitcode != 0) - savehist(histline); - } else { - if (s_find(&srec, FULLSYSNAME) == FALSE) { - logerr("Cannot find my name '%s' in %s", FULLSYSNAME, SUBFILE); - srec = dummy_srec; - } -#ifdef DOXREFS - (void) strncpy(nextref, FULLSYSNAME, BUFLEN); -#endif /* DOXREFS */ - for (ptr = nbuf; *ptr;) { - if (ngmatch(ptr,srec.s_nbuf) || index(ptr,'.') == NULL){ -#ifdef DOXREFS - while (*nextref++) - ; - (void) sprintf(--nextref, " %s:%ld", ptr, localize(ptr)); -#else /* !DOXREFS */ - (void) localize(ptr); -#endif /* !DOXREFS */ - } - while (*ptr++) - ; - } - if (firstbufname[0] == '\0') { - logerr("Newsgroups in active, but not sys"); - (void) localize("junk"); - } - } -#ifdef DOXREFS - if (index(header.nbuf, NGDELIM) == NULL) - header.xref[0] = '\0'; -#endif /* DOXREFS */ - -writeout: - /* Part 1 of kludge to get around article truncation problem */ - if ( (c=getc(infp)) != EOF) { - ungetc(c, infp); - if (c == ' ' || c == '\t') { - header.intnumlines++; - (void) sprintf(header.numlines, "%d", - header.intnumlines); - } - } - /* End of part 1 */ - if (header.expdate[0] != '\0' && mode != PROC) { - /* Make sure it's fully qualified */ - long t = cgtdate(header.expdate); - strcpy(header.expdate, arpadate(&t)); - } - - lhwrite(&header, tfp); - if ((c = getc(infp)) != EOF) { - /* Part 2 of kludge to get around article truncation problem */ - if (c == ' ' || c == '\t' ) - putc('\n', tfp); - /* End of part 2 */ - ungetc(c, infp); - while (fgets(bfr, BUFLEN, infp) != NULL) - fputs(bfr, tfp); - if (bfr[strlen(bfr)-1] != '\n') - putc('\n',tfp); - } - if (ferror(tfp)) - xerror("Write failed for temp file"); - (void) fclose(tfp); - (void) fclose(infp); - if(exitcode == 0) { - int pid; - /* article has passed all the checks, so work in background */ - if (mode != PROC) - if ((pid=vfork()) < 0) - xerror("Can't fork"); - else if (pid > 0) - exit(0); -#ifdef SIGTTOU - signal(SIGTTOU, SIG_IGN); -#endif /* SIGTTOU */ - savehist(histline); - broadcast(); - } - xxit(mode == PROC ? 0 : exitcode); -} - -input() -{ - register char *cp; - register int c; - register int empty = TRUE; - FILE *tmpfp; - int consec_newlines = 0; - int linecount = 0; - int linserted = 0; - - tmpfp = xfopen(mktemp(INFILE), "w"); - while (!SigTrap && fgets(bfr, BUFLEN, infp) != NULL) { - if (mode == PROC) { /* zap trailing empty lines */ -#ifdef ZAPNOTES - if (empty && bfr[0] == '#' && bfr[2] == ':' - && header.nf_id[0] == '\0' - && header.nf_from[0] == '\0' ) { - (void) strcpy(header.nf_id, bfr); - (void) nstrip(header.nf_id); - (void) fgets(bfr, BUFLEN, infp); - (void) strcpy(header.nf_from, bfr); - (void) nstrip(header.nf_from); - (void) fgets(bfr, BUFLEN, infp); - - if (header.numlines[0]) { - header.intnumlines -= 2; - (void) sprintf(header.numlines, "%d", header.intnumlines); - } - - /* Strip trailing " - (nf)" */ - if ((cp = rindex(header.title, '-')) != NULL - && !strcmp(--cp, " - (nf)")) - *cp = '\0'; - log("Stripped notes header on %s", header.ident); - continue; - } -#endif /* ZAPNOTES */ - if (bfr[0] == '\n' || - /* Bandage for older versions of inews */ - bfr[1] == '\n' && !isascii(bfr[0])) { - consec_newlines++; /* count it, in case */ - continue; /* but don't write it*/ - } - /* foo! a non-empty line. write out all saved lines. */ - while (consec_newlines > 0) { - putc('\n', tmpfp); - consec_newlines--; - linecount++; - } - } - if (mode != PROC && tty && strcmp(bfr, ".\n") == 0) - break; - for (cp = bfr; c = toascii(*cp); cp++) { - if (isprint(c) || isspace(c) || c == '\b') - putc(c, tmpfp); - if (c == '\n') - linecount++; - } - if (bfr[0] == '>') - linserted++; - empty = FALSE; - } - if (*filename) - (void) fclose(infp); - if (mode != PROC && linserted > (linecount-linserted)) - error("Article rejected: %s included more text than new text", - username); - - if (mode != PROC && !is_ctl && header.sender[0] == '\0') { - int siglines = 0; - char sbuf[BUFLEN]; - (void) sprintf(bfr, "%s/%s", userhome, ".signature"); - if (access(bfr, 4) == 0) { - if ((infp = fopen(bfr, "r")) == NULL) { - (void) fprintf(stderr, - "inews: \"%s\" left off (must be readable by \"inews\" owner)\n", bfr); - goto finish; - } - - while (fgets(sbuf, sizeof sbuf, infp) != NULL) - if (++siglines > 4) - break; - if (siglines > 4) - fprintf(stderr,".signature not included (> 4 lines)\n"); - else { - rewind(infp); - fprintf(tmpfp, "-- \n"); /* To separate */ - linecount++; - while ((c = getc(infp)) != EOF) { - putc(c, tmpfp); - if (c == '\n') - linecount++; - } - } - (void) fclose(infp); - } - } - -finish: - if (ferror(tmpfp)) - xerror("write failed to temp file"); - (void) fclose(tmpfp); - if (SigTrap) { - if (tty) - fprintf(stderr, "Interrupt\n"); - if (tty && !empty) - fwait(fsubr(newssave, (char *) NULL, (char *) NULL)); - if (!tty) - log("Blown away by an interrupt %d", SigTrap); - xxit(1); - } - if (tty) - fprintf(stderr, "EOT\n"); - fflush(stdout); - infp = fopen(INFILE, "r"); - if (header.numlines[0]) { - /* - * Check line count if there's already one attached to - * the article. Could make this a fatal error - - * throwing it away if it got chopped, in hopes that - * another copy will come in later with a correct - * line count. But that seems a bit much for now. - */ - if (linecount != header.intnumlines) { - if (linecount == 0) - error("%s rejected. linecount expected %d, got 0", header.ident, header.intnumlines); - if (linecount > header.intnumlines || - linecount+consec_newlines < header.intnumlines) - log("linecount expected %d, got %d", header.intnumlines, linecount+consec_newlines); - } - /* adjust count for blank lines we stripped off */ - if (consec_newlines) { - header.intnumlines -= consec_newlines; - if (header.intnumlines < 0 ) - header.intnumlines = 0; /* paranoia */ - (void) sprintf(header.numlines, "%d", header.intnumlines); - } - - } else { - /* Attach a line count to the article. */ - header.intnumlines = linecount; - (void) sprintf(header.numlines, "%d", linecount); - } -} - -/* - * Make the directory for a new newsgroup. ngname should be the - * full pathname of the directory. Do the other stuff too. - * The various games with setuid and chown are to try to make sure - * the directory is owned by NEWSUSR and NEWSGRP, which is tough to - * do if you aren't root. This will work on a UCB system (which allows - * setuid(geteuid()) or a USG system (which allows you to give away files - * you own with chown), otherwise you have to change your kernel to allow - * one of these things or run with your dirs 777 so that it doesn't matter - * who owns them. - */ -mknewsg(fulldir, ngname) -char *fulldir; -char *ngname; -{ -#ifdef USG - register char *p; - char parent[200]; - char sysbuf[200]; - struct stat sbuf; -#endif /* USG */ - - if (ngname == NULL || !isalpha(ngname[0])) - xerror("Tried to make illegal newsgroup %s", ngname); - -#ifdef USG - /* - * If the parent is 755 the setuid(getuid) - * will fail, and since mkdir is suid, and our real uid is random, - * the mkdir will fail. So we have to temporarily chmod it to 777. - */ - (void) strcpy(parent, fulldir); - while (p = rindex(parent, '/')) { - *p = '\0'; - if (stat(parent, &sbuf) == 0) { - (void) chmod(parent, 0777); - break; - } - } -#endif /* USG */ - - /* Create the directory */ - mkparents(fulldir); - if (mkdir(fulldir, 0777) < 0) - xerror("Cannot mkdir %s: %s", fulldir, errmsg(errno)); - -#ifdef USG - (void) chmod(parent, (int)sbuf.st_mode); /* put it back */ - /* - * Give away the directories we just created which were assigned - * our real uid. - */ - (void) setuid(uid); - (void) chown(fulldir, duid, dgid); - (void) strcpy(sysbuf, fulldir); - while (p = rindex(sysbuf, '/')) { - *p = '\0'; - /* stop when get to last known good parent */ - if (strcmp(sysbuf, parent) == 0) - break; - (void) chown(sysbuf, duid, dgid); - } - (void) setuid(duid); -#endif /* USG */ - - log("make newsgroup %s in dir %s", ngname, fulldir); -} - -/* - * If any parent directories of this dir don't exist, create them. - */ -mkparents(dname) -char *dname; -{ - char buf[200]; - register char *p; - - (void) strcpy(buf, dname); - p = rindex(buf, '/'); - if (p) - *p = '\0'; - if (exists(buf)) - return; - mkparents(buf); - if (mkdir(buf, 0777) < 0) - xerror("Can not mkdir %s: %s", buf, errmsg(errno)); -} - -cancel() -{ - register FILE *fp; - - log("cancel article %s", filename); - fp = fopen(filename, "r"); - if (fp == NULL) { - log("article %s not found", filename); - return; - } - if (hread(&header, fp, TRUE) == NULL) - error("Article is garbled."); - (void) fclose(fp); - (void) unlink(filename); -} - -dounspool() -{ - register DIR *dirp; - register struct direct *dir; - register int foundsome; -#ifdef VMS - sprintf(bfr, "%s/+rnews", SPOOLDIR); -#else /* !VMS */ - sprintf(bfr, "%s/.rnews", SPOOLDIR); -#endif /* !VMS */ - - if (chdir(bfr) < 0) - xerror("chdir(%s):%s", bfr, errmsg(errno)); - - do { - foundsome = 0; - dirp = opendir("."); - if (dirp == NULL) /* Boy are things screwed up */ - xerror("opendir can't open .:%s", errmsg(errno)); - - while ((dir=readdir(dirp)) != NULL) { - if (dir->d_name[0] == '.') - continue; - sprintf(bfr,"%s -S -p %s", RNEWS, dir->d_name); - system(bfr); - (void) unlink(dir->d_name); - foundsome++; - } - closedir(dirp); - } while (foundsome); /* keep rereading the directory until it's empty */ - - xxit(0); -} *-*-END-of-src/inews.c-*-* echo x - src/ifuncs.c 1>&2 sed 's/.//' >src/ifuncs.c <<'*-*-END-of-src/ifuncs.c-*-*' -/* - * This software is Copyright (c) 1986 by Rick Adams. - * - * Permission is hereby granted to copy, reproduce, redistribute or - * otherwise use this software as long as: there is no monetary - * profit gained specifically from the use or reproduction or this - * software, it is not sold, rented, traded or otherwise marketed, and - * this copyright notice is included prominently in any copy - * made. - * - * The author make no claims as to the fitness or correctness of - * this software for any use whatsoever, and it is provided as is. - * Any use of this software is at the user's own risk. - * - * ifuncs - functions used by inews. - */ - -#ifdef SCCSID -static char *SccsId = "@(#)ifuncs.c 2.57 10/29/86"; -#endif /* SCCSID */ - -#include "iparams.h" -#include <errno.h> - -/*LINTLIBRARY*/ - -#define AFSIZ 4000 /* size of text in the active file for initial malloc */ - -/* - * Transmit this article to all interested systems. - */ - -#ifdef u370 -static struct srec srec; -#endif /* u370 */ - -static struct hbuf h, hh; - -#ifdef MULTICAST -#define MAXMCAST 20 -#define MAXMCS 10 - -struct multicast { - char mc_name[SBUFLEN]; /* "multi-cast" name */ - short mc_syscnt; - char mc_tosys[MAXMCAST][SBUFLEN]; -} mcast[MAXMCS]; - -static int mccount; -#endif /* MULTICAST */ - -#ifndef DBM -char *histfile(); -#endif /* !DBM */ - -#ifdef VMS -/* - * For VMS/Eunice there are no links: article was moved to firstbufname - * before broadcast is reached. So we read it from there. - */ -extern char firstbufname[]; -#endif - -broadcast() -{ - register char *hptr; - register char *sptr; - register FILE *fp; -#ifndef u370 - struct srec srec; -#endif - char sentbuf[LBUFLEN]; - int nsent = 0; - char *sentsys; - - /* h is a local copy of the header we can scribble on */ -#ifdef VMS - fp = xfopen (firstbufname, "r"); -#else - fp = xfopen(ARTICLE, "r"); -#endif - if (hread(&h, fp, TRUE) == NULL) - xerror("Cannot reread article"); - (void) fclose(fp); - - (void) strcpy(sentbuf, h.ident); - (void) strcat(sentbuf, " sent to "); - sentsys = index(sentbuf, 0); - nsent = 0; - /* break path into list of systems. */ - sptr = hptr = h.path; - while ((hptr=strpbrk(hptr, NETCHRS)) != NULL) { - *hptr++ = '\0'; - sptr = hptr; - } - *sptr = '\0'; - -#ifdef MULTICAST - mccount = 0; -#endif /* MULTICAST */ - - /* loop once per system. */ - s_openr(); - while (s_read(&srec)) { - char *dist = h.distribution; -#ifdef HIDDENNET - if (strncmp(srec.s_name, LOCALSYSNAME, SNLN) == 0) - continue; -#endif /* HIDDENNET */ - if (strncmp(srec.s_name, FULLSYSNAME, SNLN) == 0) - continue; - if (sptr = srec.s_nosend) { - while (*sptr) { - while (*sptr && *sptr != ',') - sptr++; - if (*sptr == ',') - *sptr++ = '\0'; - } - *++sptr = '\0'; - } - hptr = h.path; - while (*hptr != '\0') { - if (strncmp(srec.s_name, hptr, SNLN) == 0) - goto contin; - if (sptr = srec.s_nosend) { - while (*sptr != '\0') { - if (strncmp(sptr, hptr, SNLN) == 0) - goto contin; - while (*sptr++) - ; - } - } - while (*hptr++ != '\0') - ; - } - if (!ngmatch(h.nbuf, srec.s_nbuf)) - continue; - if (*dist == '\0') - dist = "world"; - if (!ngmatch(dist, srec.s_nbuf) && !ngmatch(srec.s_nbuf, dist)) - continue; - - if (nsent) { - hptr = sentsys; - while ((sptr = index(hptr, ',')) != NULL) { - *sptr = '\0'; - if (strcmp(hptr, srec.s_name) == 0) { - *sptr = ','; - goto contin; - } - *sptr++ = ','; - for (hptr = sptr; isspace(*hptr); hptr++) - ; - } - if (strcmp(hptr, srec.s_name) == 0) - continue; - } - /* now we've found a system to send this article to */ -#ifdef MULTICAST - if (index(srec.s_flags, 'M')) { - /* do a "multi-cast" transmit */ - register struct multicast *m; - - if (strlen(srec.s_name) >= SBUFLEN || - strlen(srec.s_xmit) >= SBUFLEN) - xerror("system name too long for multicast"); - for (m = mcast; m < &mcast[mccount]; m++) - if (strcmp(srec.s_xmit, m->mc_name) == 0) - break; - if (m >= &mcast[MAXMCS]) - xerror("Too many multicasts"); - if (m == &mcast[mccount]) { - mccount++; - m->mc_syscnt = 0; - strcpy(m->mc_name, srec.s_xmit); - } - if (m->mc_syscnt >= MAXMCAST) - xerror("Too many systems for multicast"); - strcpy(m->mc_tosys[m->mc_syscnt++], srec.s_name); - } else { - register struct multicast *m; - register char **yptr; - char *sysptrs[MAXMCAST]; - int mc; - - mc = 0; - for (m = mcast; m < &mcast[mccount]; m++) - if (strcmp(m->mc_name, srec.s_name) == 0) { - yptr = sysptrs; - while (mc < m->mc_syscnt) - *yptr++ = m->mc_tosys[mc++]; - break; - } -#ifdef VMS - if (!transmit(&srec, xfopen(firstbufname,"r"), 1, - sysptrs, mc)) -#else /* !VMS */ - if (!transmit(&srec, xfopen(ARTICLE,"r"), 1, sysptrs, - mc)) -#endif /* !VMS */ - continue; - } -#else /* !MULTICAST */ -#ifdef VMS - if (!transmit(&srec, xfopen(firstbufname, "r"), -#else /* !VMS */ - if (!transmit(&srec, xfopen(ARTICLE, "r"), -#endif /* !VMS */ - (strncmp(h.nbuf, "to.", 3) != 0), - (char **) NULL, FALSE)) - continue; -#endif /* !MULTICAST */ - if (nsent) - (void) strcat(sentbuf, ", "); - (void) strcat(sentbuf, srec.s_name); - nsent++; - contin:; - } - if (nsent) - log(sentbuf); - s_close(); -} - -/* - * Transmit file to system. - */ -#define PROC 0004 -#ifndef MULTICAST -/* ARGSUSED */ -#endif /* !MULTICAST */ -transmit(sp, ifp, maynotify, sysnames, mc) -register struct srec *sp; -register FILE *ifp; -int maynotify; -char **sysnames; -int mc; -{ - register FILE *ofp; - register int c; - register char *ptr; - char TRANS[BUFLEN]; - char *argv[20]; - register int pid; - extern char firstbufname[]; - -/* A: afmt: the other machine runs an A news, so we xmit in A format */ - int afmt = (index(sp->s_flags, 'A') != NULL); -/* B: use B format (this is the default - don't use this letter elsewise). */ -/* F: append name to file */ - int appfile = (index(sp->s_flags, 'F') != NULL); -/* L: local: don't send the article unless it was generated locally */ - int local = ((ptr = index(sp->s_flags, 'L')) != NULL); -/* H: interpolate history line into command, use existing file */ - int history = (index(sp->s_flags, 'H') != NULL); -/* m: moderated: only send if group is moderated */ - int sendifmoderated = (index(sp->s_flags, 'm') != NULL); -/* u: unmoderated: only send if group is unmoderated */ - int sendifunmoderated = (index(sp->s_flags, 'u') != NULL); -/* M: multi-cast: this is taken care of above, but don't reuse flag */ -#ifdef MULTICAST -/* O: multi-cast only, don't send article if not multicast hosts */ - int multisend = (index(sp->s_flags, 'O') != NULL); -#endif /* MULTICAST */ -/* N: notify: don't send the article, just tell him we have it */ - int notify = maynotify && (index(sp->s_flags, 'N') != NULL); -/* S: noshell: don't fork a shell to execute the xmit command */ - int noshell = (index(sp->s_flags, 'S') != NULL); -/* U: useexist: use the -c option to uux to use the existing copy */ - int useexist = (index(sp->s_flags, 'U') != NULL); -/* I: append messageid to file. implies F flag */ - int appmsgid = maynotify && (index(sp->s_flags, 'I') != NULL); - - if (notify) - appfile = appmsgid = FALSE; - - if (!appfile) - appfile = appmsgid; - - if (local && mode == PROC) { - local = 0; - while (isdigit(*++ptr)) - local = local * 10 + *ptr - '0'; - for (ptr = h.path; *ptr != '\0' && local >= 0; local--) - while (*ptr++ != '\0') - ; - if (local < 0) { - (void) fclose(ifp); - return FALSE; - } - } - - /* - ** Do not transmit to system specified in -x flag. - */ - if (not_here[0] && strcmp(not_here, sp->s_name) == 0) { - (void) fclose(ifp); - return FALSE; - } - -#ifdef DEBUG - printf("Transmitting to '%s'\n", sp->s_name); -#endif /* DEBUG */ - -#ifdef MULTICAST - if (multisend && mc == 0) { - (void) fclose(ifp); - return FALSE; - } -#endif /* MULTICAST */ - - if ((sendifmoderated && is_mod[0] == '\0') || - (sendifunmoderated && is_mod[0] != '\0')) { - fclose(ifp); - return FALSE; - } - - if (appmsgid || (!appfile && !useexist && !history)) { - if (!hread(&hh, ifp, TRUE)) { - logerr("Bad header, not transmitting %s re %s to %s", - hh.ident, hh.title, sp->s_name); - (void) fclose(ifp); - return FALSE; - } - if (hh.nbuf[0] == '\0') { - fprintf(stderr, "Article not subscribed to by %s\n", sp->s_name); - (void) fclose(ifp); - return FALSE; - } - (void) sprintf(TRANS, "%s/trXXXXXX", SPOOL); - } - - if (notify) { - char oldid[50]; - (void) sprintf(hh.title, "ihave %s %s", hh.ident, FULLSYSNAME); - (void) strcpy(hh.ctlmsg, hh.title); - (void) strcpy(hh.numlines, "0"); - (void) sprintf(hh.nbuf, "to.%s.ctl", sp->s_name); - (void) strcpy(oldid, hh.ident); - getident(&hh); - log("tell %s about %s, notif. id %s", - sp->s_name, oldid, hh.ident); - } - - if (appfile) { - if (firstbufname[0] == '\0') { - extern char histline[]; - localize("junk"); - savehist(histline); - xerror("No file name to xmit from"); - } - if (sp->s_xmit[0] == '\0') - sprintf(sp->s_xmit, "%s/%s%s", BATCHDIR, sp->s_name, - appmsgid ? ".ihave" : ""); -#ifdef IHCC - (void) sprintf(TRANS, "%s/%s/%s", logdir(HOME), BATCHDIR, sp->s_xmit); - ofp = fopen(TRANS, "a"); -#else /* !IHCC */ - ofp = fopen(sp->s_xmit, "a"); -#endif /* !IHCC */ - if (ofp == NULL) - xerror("Cannot append to %s", sp->s_xmit); - fprintf(ofp, "%s", appmsgid ? hh.ident : firstbufname); -#ifdef MULTICAST - while (--mc >= 0) - fprintf(ofp, " %s", *sysnames++); -#endif /* !MULTICAST */ - putc('\n', ofp); - (void) fclose(ofp); - (void) fclose(ifp); - return TRUE; - } - else if (useexist) { - if (firstbufname[0] == '\0') - xerror("No file name to xmit from"); - if (*sp->s_xmit == '\0') -#ifdef UXMIT - (void) sprintf(bfr, UXMIT, sp->s_name, firstbufname); -#else - xerror("UXMIT not defined for U flag"); -#endif - else -#ifdef MULTICAST - makeargs(bfr, sp->s_xmit, firstbufname, sysnames, mc); -#else - (void) sprintf(bfr, sp->s_xmit, firstbufname); -#endif - (void) fclose(ifp); - } else if (history) { - extern char histline[]; - - if (*sp->s_xmit == '\0') - xerror("no xmit command with H flag"); -#ifdef MULTICAST - makeargs(bfr, sp->s_xmit, histline, sysnames, mc); -#else - (void) sprintf(bfr, sp->s_xmit, histline); -#endif - } else { - ofp = xfopen(mktemp(TRANS), "w"); - if (afmt) { -#ifdef OLD - fprintf(ofp, "A%s\n%s\n%s!%s\n%s\n%s\n", oident(hh.ident), hh.nbuf, FULLSYSNAME, - hh.path, hh.subdate, hh.title); -#else /* !OLD */ - logerr("Must have OLD defined to use A flag for xmit"); - return FALSE; -#endif /* !OLD */ - } else - hwrite(&hh, ofp); - if (!notify) - while ((c = getc(ifp)) != EOF) - putc(c, ofp); - if (ferror(ofp)) - xerror("write failed on transmit"); - (void) fclose(ifp); - (void) fclose(ofp); - if (*sp->s_xmit == '\0') - (void) sprintf(bfr, DFTXMIT, sp->s_name, TRANS); - else -#ifdef MULTICAST - makeargs(bfr, sp->s_xmit, TRANS, sysnames, mc); -#else /* !MULTICAST */ - (void) sprintf(bfr, sp->s_xmit, TRANS); -#endif /* !MULTICAST */ - } - - /* At this point, the command to be executed is in bfr. */ - if (noshell) { - if (pid = vfork()) - fwait(pid); - else { - (void) close(0); - (void) open(TRANS, 0); - ptr = bfr; - for (pid = 0; pid < 19; pid++) { - while (isspace(*ptr)) - *ptr++ = 0; - argv[pid] = ptr; - while (!isspace(*++ptr) && *ptr) - ; - if (!*ptr) - break; - } - argv[++pid] = 0; - (void) setgid(gid); - (void) setuid(uid); - execv(argv[0], argv); - xerror("Can't execv %s", argv[0]); - } - } else { - if (!history && sp->s_xmit[0] && !index(bfr, '<')) { - char newcmd[LBUFLEN]; - - (void) sprintf(newcmd, "(%s) <%s", bfr, - useexist ? firstbufname : TRANS); - system(newcmd); - } else - system(bfr); - } - if (!appfile && !useexist && !history) - (void) unlink(TRANS); - (void) fclose(ifp); - return TRUE; -} - -#ifdef MULTICAST -makeargs(buf, cmd, arg2, sysargs, sac) -char *buf; -char *cmd; -char *arg2; -register char **sysargs; -int sac; -{ - register char *p = cmd; - register char *q; - register ac = 0; - register char *b = buf; - - q = p; - do { - if (q = index(q, ' ')) - *q = '\0'; - if (index(p, '%')) { - switch (++ac) { - case 1: - while (--sac >= 0) { - sprintf(b, p, *sysargs++); - b = index(b, '\0'); - } - break; - case 2: - sprintf(b, p, arg2); - b = index(b, '\0'); - break; - default: - if (q) - *q = ' '; - xerror("badly formed command: %s", cmd); - } - } else { - strcpy(b, p); - b = index(b, '\0'); - } - if (q) { - *q = ' '; - p = q; - while (isspace(*q)) - q++; - } - } while (q != NULL); -} -#endif /* MULTICAST */ - -typedef struct { - char *dptr; - int dsize; -} datum; - -/* - * Return TRUE if we have seen this file before, else FALSE. - */ -history(hp) -struct hbuf *hp; -{ -#ifdef DBM - datum lhs, rhs; - datum fetch(); -#else /* !DBM */ - register FILE *hfp; - register char *p; -#endif /* !DBM */ - char lcident[BUFLEN]; - extern char histline[]; - -#ifdef DEBUG - fprintf(stderr,"history(%s)\n", hp->ident); -#endif /* DEBUG */ - /* - * Make the article ID case insensitive. - */ - (void) strcpy(lcident, hp->ident); - lcase(lcident); - - idlock(lcident); -#ifdef DBM - initdbm(ARTFILE); - lhs.dptr = lcident; - lhs.dsize = strlen(lhs.dptr) + 1; - rhs = fetch(lhs); - if (rhs.dptr) - return(TRUE); -#else /* !DBM */ - hfp = xfopen(histfile(lcident), "r"); - while (fgets(bfr, BUFLEN, hfp) != NULL) { - p = index(bfr, '\t'); - if (p == NULL) - p = index(bfr, '\n'); - if (p != NULL) /* can happen if nulls in file */ - *p = 0; - lcase(bfr); - - if (strcmp(bfr, lcident) == 0) { - (void) fclose(hfp); - idunlock(); -#ifdef DEBUG - fprintf(stderr,"history returns true\n"); -#endif /* DEBUG */ - return TRUE; - } - } - (void) fclose(hfp); -#endif /* !DBM */ - histline[0] = '\0'; - addhist(hp->ident); - addhist("\t"); -#ifdef DEBUG - fprintf(stderr,"history returns false\n"); -#endif - return FALSE; -} - -char histline[PATHLEN]; - -addhist(msg) -char *msg; -{ - (void) strcat(histline, msg); -} - -savehist(hline) -char *hline; -{ - register FILE *hfp; - datum lhs, rhs; - long fpos; - register char *p; - - hfp = xfopen(ARTFILE, "a"); - (void) fseek(hfp, 0L, 2); /* Unisoft 5.1 doesn't seek to EOF on 'a' */ - fpos = ftell(hfp); - fprintf(hfp, "%s\n", hline); - (void) fclose(hfp); -#ifdef DBM - /* We assume that history has already been called, calling dbminit. */ - p = index(hline, '\t'); - if (p) - *p = 0; - lcase(hline); - lhs.dptr = hline; - lhs.dsize = strlen(lhs.dptr) + 1; - rhs.dptr = (char *)&fpos; - rhs.dsize = sizeof fpos; - store(lhs, rhs); -#else /* !DBM */ - /* also append to proper history subfile */ - hfp = xfopen(histfile(hline), "a"); - fprintf(hfp, "%s\n", hline); - (void) fclose(hfp); -#endif /* !DBM */ - idunlock(); -} - -/* - * Save partial news. - */ -/* ARGSUSED */ -newssave(fd, dummy) -FILE *fd; -char *dummy; -{ - register FILE *tofd, *fromfd; - char sfname[BUFLEN]; - register int c; - time_t tim; - - if (fd == NULL) - fromfd = xfopen(INFILE, "r"); - else - fromfd = fd; - (void) umask(savmask); - (void) setgid(gid); - (void) setuid(uid); - - (void) sprintf(sfname, "%s/%s", userhome, PARTIAL); - if ((tofd = fopen(sfname, "a")) == NULL) - xerror("Cannot save partial news in %s", sfname); - (void) time(&tim); - fprintf(tofd, "----- News saved at %s\n", arpadate(&tim)); - while ((c = getc(fromfd)) != EOF) - putc(c, tofd); - (void) fclose(fromfd); - (void) fclose(tofd); - printf("News saved in %s\n", sfname); - xxit(1); -} - -/* - * Handle dates in header. - */ - -dates(hp) -struct hbuf *hp; -{ - time_t edt; - - if (*hp->subdate) { - if (cgtdate(hp->subdate) < 0) { - error("Cannot parse submittal date '%s'", hp->subdate); - } - } else { - (void) time(&edt); - (void) strcpy(hp->subdate, arpadate(&edt)); - } -} - -#define LOCKSIZE 128 -char lockname[LOCKSIZE]; - -idlock(str) -char *str; -{ - register int i; - register char *cp, *scp; - char tempname[LOCKSIZE]; - time_t now; - struct stat sbuf; - extern int errno; -#ifdef VMS - int fd; - - (void) sprintf(lockname, "/tmp/%s.l.1", str); - while ((fd = creat(lockname, 0444)) < 0) { -#else /* !VMS */ - (void) strcpy(tempname, "/tmp/LTMP.XXXXXX"); - (void) mktemp(tempname); - (void) strcpy(lockname, "/tmp/L"); - i = strlen(lockname); - cp = &lockname[i]; - scp = str - 1; - while (i++ < LOCKSIZE && *++scp != '\0') - if (*scp == '/') /* slash screws up the open */ - *cp++ = '.'; - else - *cp++ = *scp; - *cp = '\0'; -#ifdef FOURTEENMAX - lockname[5 /* /tmp/ */ + 14] = '\0'; -#endif - i = creat(tempname, 0666); - if (i < 0) - xerror("Cannot creat %s: errno %d", tempname, errno); - (void) close(i); - while (link(tempname, lockname)) { -#endif /* !VMS */ - (void) time(&now); - if (stat(lockname, &sbuf) < 0) - xerror("Directory permission problem in /tmp"); - - if (sbuf.st_mtime + 10*60 < now) { - (void) unlink(lockname); - logerr("Article %s locked up", str); - break; - } - log("waiting on lock for %s", lockname); - sleep((unsigned)60); - } -#ifdef VMS - (void) close(fd); -#endif - (void) unlink(tempname); -} - -idunlock() -{ - (void) unlink(lockname); -} - -/* - * Put a unique name into header.ident. - */ -getident(hp) -struct hbuf *hp; -{ - long seqn; - register FILE *fp; - - lock(); - fp = xfopen(SEQFILE, "r"); - (void) fgets(bfr, BUFLEN, fp); - (void) fclose(fp); - seqn = atol(bfr) + 1; -/* - * For Eunice, this breaks if SEQFILE is not in Unix format. - */ - fp = xfopen(SEQFILE, "r+w"); - fprintf(fp, "%ld\n", seqn); - (void) fclose(fp); - unlock(); -#ifdef HIDDENNET - if (strcmp(LOCALSYSNAME, FULLSYSNAME)) - (void) sprintf(hp->ident, "<%ld@%s.%s%s>", seqn, LOCALSYSNAME, FULLSYSNAME, - MYDOMAIN); - else -#endif /* !HIDDENNET */ - (void) sprintf(hp->ident, "<%ld@%s%s>", seqn, FULLSYSNAME, MYDOMAIN); -} - -/* - * Check that header.nbuf contains only valid newsgroup names; - * exit with error if not valid. - */ -ngfcheck(isproc) -{ - register FILE * f; - register char * cp; - register int i, j; - register int ngcount, okcount, havealiased; - register int pass; - char * ngs[sizeof header.nbuf / 2]; - char uses[sizeof header.nbuf / 2]; - char tbuf[sizeof header.nbuf]; - char abuf[BUFLEN]; - - havealiased = ngcount = 0; - is_mod[0] = '\0'; - /* - ** Split header.nbuf into constituent newsgroups. - ** Zap "local" newsgroups of articles from remote sites. - */ - cp = tbuf; - (void) strcpy(cp, header.nbuf); - for ( ; ; ) { - while (*cp == NGDELIM || *cp == ' ') - ++cp; - if (*cp == '\0') - break; - ngs[ngcount] = cp; - do { - ++cp; - } while (*cp != '\0' && *cp != NGDELIM && *cp != ' '); - if (*cp != '\0') - *cp++ = '\0'; - /* - ** Check for local only distribution on incoming - ** newsgroups. This might occur if someone posted to - ** general,net.unix - */ - if (isproc && index(ngs[ngcount], '.') == NULL && - index(header.nbuf, '.') != NULL) { - logerr("Local group '%s' removed", - ngs[ngcount]); - continue; - } - uses[ngcount] = 1; /* it should go in "Newsgroups" line */ - ++ngcount; - } - /* - ** Check groups against active file. - */ -recheck: - okcount = 0; - rewind(actfp); clearerr(actfp); - while (okcount < ngcount && fgets(bfr, BUFLEN, actfp) == bfr) { - if ((cp = index(bfr, ' ')) == NULL) - continue; /* strange line in input! */ - /* newsgroup 12345 12345 X */ - /* cp + 01234567890123 */ - if (!isproc && cp[13] == 'n') - continue; /* can't post to this group! */ - *cp = '\0'; - for (i = 0; i < ngcount; ++i) - if (uses[i] >= 1 && strcmp(bfr, ngs[i]) == 0) { - uses[i] = 2; /* it should be localized too */ - if (cp[13] == 'm') - strcpy(is_mod, bfr); - ++okcount; - } - } -#ifdef ALWAYSALIAS - okcount = 0; -#endif /* ALWAYSALIAS */ - /* - ** Handle groups absent from active file. - */ - if (havealiased == 0 && okcount < ngcount) { - /* - ** See if remaining groups are in our alias list. - */ - f = xfopen(ALIASES, "r"); - while (okcount < ngcount && fscanf(f, "%s %s", abuf, bfr) == 2) - for (i = 0; i < ngcount; ++i) { -#ifndef ALWAYSALIAS - if (uses[i] == 2) - continue; -#endif /* ALWAYSALIAS */ - if (strcmp(ngs[i], abuf) != 0) - continue; - if (isproc) - cp = "Aliased newsgroup %s to %s"; - else - cp = "Please change %s to %s"; - logerr(cp, abuf, bfr); - ngs[i] = AllocCpy(bfr); - uses[i] = 2; - ++havealiased; - ++okcount; - } - (void) fclose(f); - for (i = 0; i < ngcount; ++i) { - if (uses[i] == 2) - continue; - if (isproc) - cp = "Unknown newsgroup '%s' not localized"; - else - cp = "Unknown newsgroup '%s'"; - logerr(cp, ngs[i]); -#ifdef ALWAYSALIAS - ++okcount; /* so we know to exit below */ - } - if (!isproc && okcount > 0) -#else /* !ALWAYSALIAS */ - } - if (!isproc) -#endif /* !ALWAYSALIAS */ - newssave(infp, (char *) NULL); - /* - * Unfortunately, if you alias an unmoderated group to a - * moderated group, you must recheck the active file to see - * if the new group is moderated. Rude but necessary. - */ - if (havealiased) - goto recheck; - } - /* - ** Zap duplicates. - */ - for (i = 0; i < ngcount - 1; ++i) { - if (uses[i] == 0) - continue; - for (j = i + 1; j < ngcount; ++j) { - if (uses[j] == 0) - continue; - if (strcmp(ngs[i], ngs[j]) != 0) - continue; - logerr("Duplicate '%s' removed", ngs[j]); - if (uses[i] < uses[j]) - uses[i] = uses[j]; - uses[j] = 0; - } - } - for (pass = 1; pass <= 2; ++pass) { - register int avail; - - if (pass == 1) { - /* - ** Rewrite header.nbuf. - */ - cp = header.nbuf; - avail = sizeof header.nbuf; - } else { - /* - ** Fill in nbuf. - */ - cp = nbuf; - avail = sizeof nbuf; - } - for (i = 0; i < ngcount; ++i) { - if (uses[i] < pass) - continue; - j = strlen(ngs[i]); - if (j + 2 > avail) { - logerr("Redone Newsgroups too long"); - break; - } - (void) strcpy(cp, ngs[i]); - cp += j; - *cp++ = (pass == 1) ? NGDELIM : '\0'; - avail -= (j + 1); - } - if (pass == 1) { - if (cp == header.nbuf) - *cp = '\0'; - else *(cp - 1) = '\0'; - } else *cp = '\0'; - } - /* - ** Free aliases. - */ - for (i = 0; i < ngcount; ++i) - if (ngs[i] < tbuf || ngs[i] > &tbuf[sizeof tbuf - 1]) - free(ngs[i]); - return nbuf[0] == '\0'; -} - -/* - * Figure out who posted the article (which is locally entered). - * The results are placed in the header structure hp. - */ -gensender(hp, logname) -struct hbuf *hp; -char *logname; -{ - register char *fn, *p; - char buf[BUFLEN]; - char *fullname(), *getenv(); - int fd, n; - - if ((fn = getenv("NAME")) == NULL) { - (void) sprintf(buf, "%s/%s", userhome, ".name"); - if ((fd = open(buf, 0)) >= 0) { - n = read(fd, buf, sizeof buf); - (void) close(fd); - if (n > 0 && buf[0] >= 'A') { - for (p = fn = buf; *p; p++) - if (*p < ' ') - *p = '\0'; - } - } - } - - if (fn == NULL) - fn = fullname(logname); - - (void) sprintf(hp->path, "%s", logname); - (void) sprintf(hp->from, "%s@%s%s (%s)", logname, FULLSYSNAME, MYDOMAIN, fn); -} - -/* - * Trap interrupts. - */ -onsig(n) -int n; -{ - static int numsigs = 0; - /* - * Most UNIX systems reset caught signals to SIG_DFL. - * This bad design requires that the trap be set again here. - * Unfortunately, if the signal recurs before the trap is set, - * the program will die, possibly leaving the lock in place. - */ - if (++numsigs > 100) { - logerr("inews ran away looping on signal %d", n); - xxit(1); - } - (void) signal(n, onsig); - SigTrap = n; -} - -#ifdef BATCH -/* - * If the stdin begins with "#", we assume we have been fed a batched - * shell script which looks like this: - * #! rnews 1234 - * article with 1234 chars - * #! rnews 4321 - * article with 4321 chars - * - * In this case we just exec the unbatcher and let it unpack and call us back. - * - * Note that there is a potential security hole here. If the batcher is - * /bin/sh, someone could ship you arbitrary stuff to run as shell commands. - * The main protection you have is that the effective uid will be news, not - * uucp and not the super user. (That, plus the fact that BATCH is set to - * "unbatch" as the system is distributed.) If you want to run a batched link - * and you are security conscious, do not use /bin/sh as the unbatcher. - * the thing to do is to change BATCH in your localize.sh file from /bin/sh - * to some restricted shell which can only run rnews. - */ -checkbatch() -{ - int c; - - c = getc(infp); - if (c != EOF) - (void) ungetc(c, infp); - clearerr(infp); - if (c == '#') { - char cmd[BUFLEN], unbatcher[BUFLEN], arg1[BUFLEN], arg2[BUFLEN]; - register char *cp; - int n; - - reset_infp(); - /* - * For efficiency, try and recognize the most common - * forms of batching and exec them directly - */ - n = read(0, cmd, BUFLEN-1); - if (n <= 0) /* Can't happen */ - xerror("can't read stdin to unbatch"); - cmd[n] = '\0'; - cp = index(cmd, '\n'); - if (cp) - *cp = '\0'; - /* now put stdin at the "right" place for the exec */ - (void) lseek(0,1L+(long)(cp - cmd), 0); - if( strncmp(cmd, "#! cunbatch", 11) == 0) { - (void) strcpy(unbatcher, "/bin/sh"); - (void) strcpy(arg1, "-c"); - (void) sprintf(arg2, "%s/compress -d | %s/%s", - LIB, LIB, BATCH); - } else if (strncmp(cmd, "#! c7unbatch", 12) == 0) { - (void) strcpy(unbatcher, "/bin/sh"); - (void) strcpy(arg1, "-c"); - (void) sprintf(arg2, - "%s/decode | %s/compress -d | %s/%s", - LIB, LIB, LIB, BATCH); - } else { - (void) lseek(0, 0L, 0); - (void) sprintf(unbatcher, "%s/%s", LIB, BATCH); - arg1[0] = '\0'; - arg2[0] = '\0'; - } - execl(unbatcher, "news-unpack", arg1, arg2, (char *)0); - xerror("Unable to exec %s to unpack news.", unbatcher); - } -} - -/* - * We've already done a read on stdin, and we want to seek back to the - * beginning. We want the real file descriptor (beyond buffers) to - * reflect the true beginning. Do whatever is necessary. - */ -reset_infp() -{ - register FILE *ofd; - register int c; - char *ofdname; - long lseek(); - - /* First try to seek back - if so, it's a cheap way back. */ - if (lseek(0, 0L, 0) == 0L) - return; - - /* Can't seek, so have to copy input to a file and use that. */ - ofdname = "/tmp/inewsXXXXXX"; - (void) mktemp(ofdname); - ofd = fopen(ofdname, "w"); - while ((c=getc(infp)) != EOF) - putc(c, ofd); - if (ferror(ofd)) - xerror("write failed on temp file %s", ofdname); - (void) fclose(ofd); - (void) fclose(infp); - - /* Now for a few lower level hacks to reopen stdin and make - * absolutely sure that the right fd's are done for the exec. - */ - (void) close(0); /* make sure stdin is really closed. */ - (void) open(ofdname, 0); - (void) unlink(ofdname); /* to avoid cleaning it up later. */ -} -#endif /* BATCH */ - -/* - * Exit and cleanup. - */ -xxit(status) -int status; -{ - (void) unlink(INFILE); - (void) unlink(ARTICLE); - while (lockcount > 0) - unlock(); - idunlock(); - exit(status); -} - -rwaccess(fname) -char *fname; -{ - int fd; - - fd = open(fname, 2); - if (fd < 0) - return 0; - (void) close(fd); - return 1; -} - -exists(fname) -char *fname; -{ - int fd; - - fd = open(fname, 0); - if (fd < 0) - return 0; - (void) close(fd); - return 1; -} - -int lockcount = 0; /* no. of times we've called lock */ - -#ifdef VMS - -#define SUBLOCK "/tmp/netnews.lck.1" - -/* - * Newsystem locking. - * These routines are different for VMS because we can not - * effectively simulate links, and VMS supports multiple - * version numbers of files - */ -lock() -{ - register int i; - register int fd; - - if (lockcount++ == 0) { - i = DEADTIME; - while ((fd = creat(SUBLOCK, 0444)) < 0) { - if (--i < 0) { - (void) unlink(SUBLOCK); - logerr("News system locked up"); - } - if (i < -3) - xerror("Unable to unlock news system"); - sleep((unsigned)1); - } - (void) close(fd); - } -} - -unlock() -{ - if (--lockcount == 0) - (void) unlink(SUBLOCK); -} - -#else /* !VMS */ - -/* - * Newsystem locking. - */ - -#if defined(BSD4_2) || defined(LOCKF) -#ifdef LOCKF -#include <unistd.h> -#else /* !LOCKF */ -#include <sys/file.h> -#endif /* !LOCKF */ -static int LockFd = -1; -lock() -{ - LockFd = open(SUBFILE,0); - /* This will sleep until the other program releases the lock */ - /* We may need to alarm out of this, but I don't think so */ -#ifdef LOCKF - (void) lockf(LockFd, F_LOCK, 0); -#else - (void) flock(LockFd, LOCK_EX); -#endif -} - -unlock() -{ - (void) close(LockFd); -} -#else /* !BSD4_2 */ -lock() -{ - register int i; - extern int errno; - - if (lockcount++ == 0) { - i = DEADTIME; - while (link(SUBFILE, LOCKFILE)) { - if (errno != EEXIST) - break; - if (--i < 0) - xerror("News system locked up"); - sleep((unsigned)1); - } - } -} - -unlock() -{ - if (--lockcount == 0) - (void) unlink(LOCKFILE); -} -#endif /* !BSD4_2 */ -#endif /* !VMS */ - -/* - * Generate the name of the person responsible for posting this article, - * in order to check that two articles were posted by the same person. - */ -char * -senderof(hp) -struct hbuf *hp; -{ - register char *r, *q, *tp; - char *tailpath(); - - if (hp->sender[0]) - tp = hp->sender; - else if (hp->from[0]) - tp = hp->from; - else - tp = tailpath(hp); - - /* Remove full name */ - q = index(tp, ' '); - if (q) - *q = '\0'; - - r = AllocCpy(tp); - if (q != NULL) - *q = ' '; - return r; -} - -/* VARARGS1 */ -error(message, arg1, arg2, arg3) -char *message; -long arg1, arg2, arg3; -{ - char buffer[LBUFLEN]; - - fflush(stdout); - (void) sprintf(buffer, message, arg1, arg2, arg3); - logerr(buffer); - xxit(mode == PROC ? 0 : 1); -} *-*-END-of-src/ifuncs.c-*-* echo x - src/patchlevel.h 1>&2 sed 's/.//' >src/patchlevel.h <<'*-*-END-of-src/patchlevel.h-*-*' -0 *-*-END-of-src/patchlevel.h-*-* echo x - src/localize.sh 1>&2 sed 's/.//' >src/localize.sh <<'*-*-END-of-src/localize.sh-*-*' *-*-END-of-src/localize.sh-*-* exit