news 2.10.2 src part 2
Rick Adams
rick at seismo.UUCP
Tue Sep 4 13:08:19 AEST 1984
if test ! -d src
then
mkdir src
fi
echo x - src/csendbatch.sh
sed 's/^X//' >src/csendbatch.sh <<'*-*-END-of-src/csendbatch.sh-*-*'
X: '@(#)csendbatch 1.3 8/21/84'
Xfor rmt in $*
Xdo
X while test $? -eq 0 -a \( -s BATCHDIR/$rmt -o -s BATCHDIR/$rmt.work \)
X do
X LIBDIR/batch BATCHDIR/$rmt 100000 | LIBDIR/compress -q | \
X if test -s BATCHDIR/$rmt.cmd
X then
X BATCHDIR/$rmt.cmd
X else
X uux - UUXFLAGS $rmt!cunbatch
X fi
X done
Xdone
*-*-END-of-src/csendbatch.sh-*-*
echo x - src/cunbatch.sh
sed 's/^X//' >src/cunbatch.sh <<'*-*-END-of-src/cunbatch.sh-*-*'
Xexec LIBDIR/compress -d | BINDIR/rnews
*-*-END-of-src/cunbatch.sh-*-*
echo x - src/defs.dist
sed 's/^X//' >src/defs.dist <<'*-*-END-of-src/defs.dist-*-*'
X/*
X * defs.h - defines for news-related programs.
X *
X * If you remove any lines here or in your Makefile, make the change
X * to localize.sh so you won't have to redo it for each news release.
X *
X * If TMAIL is undefined, the -M option will be disabled.
X *
X * By convention, the version of the software you are running is taken
X * to be news_version below.
X */
X
X/* @(#)defs.dist 2.34 9/3/84 */
X
X#define NEWS_VERSION "B 2.10.2 9/3/84"
X
X#define DAYS (60L*60L*24L)
X#define WEEKS (7*DAYS)
X/* Things that very well may require local configuration */
X#ifndef HOME
X#define ROOTID 10 /* uid of person allowed to cancel anything */
X#endif
X#define N_UMASK 000 /* mask for umask call, 022 for secure system */
X#define DFLTEXP 2*WEEKS /* default no. of seconds to expire in */
X#define DFLTSUB "general,all.general" /* default subscription list */
X#define TMAIL "/usr/ucb/Mail" /* Mail program that understands -T */
X#define ADMSUB "general,all.announce" /* Mandatory subscription list */
X#define PAGE "/usr/ucb/more" /* Default pager */
X#define NOTIFY "usenet" /* Tell him about certain ctl messages */
X /* Default xmit command - remove -z if */
X#define DFTXMIT "uux - -r -z %s!rnews < %s" /* your uux can't do it */
X#define UXMIT "uux -r -z -c %s!rnews '<' %s" /* If uux -c is ok */
X#define DFTEDITOR "vi" /* Default editor, see also postnews. */
X/* #define UUPROG "euuname" /* omit for uuname, put in LIBDIR */
X#define MANUALLY /* Don't execute rmgroups, just notify. */
X#define BATCH "unbatch" /* name of unbatcher */
X/* #define LOCALNAME /* There is no full name database. */
X/* #define INTERNET /* Internet mail works locally */
X#define MYDOMAIN ".UUCP" /* Local domain */
X/* #define CHEAP /* don't chown files to news */
X/* #define OLD /* Add extra headers for old neighbors */
X/* #define UNAME /* If uname call is available. */
X/* #define GHNAME /* If gethostname call is available. */
X#define V7MAIL /* Local mail format is V7 ("From ") */
X#define SORTACTIVE /* if you want news presented in the order of the .newsrc */
X#define ZAPNOTES /* if you want old style notes headers moved into the headers */
X/* #define BSD4_2 /* If you are running 4.2 BSD */
X/* #define BSD4_1C /* If you are running 4.1C BSD */
X/* #define SENDMAIL "/usr/lib/sendmail -oi -oem" /* command line to run "sendmail" if you have it */
X#define MYORG "Frobozz Inc., St. Louis" /* My organization. Please */
X /* include your city (and state, and */
X /* country, if not obvious) in MYORG, */
X /* and please keep it short. */
X
X/* Things you might want to change */
X#define NEWSRC ".newsrc" /* name of .newsrc file (in home dir) */
X#define LINES 512 /* maximum no. of lines in .newsrc */
X#define NEGCHAR '!' /* newsgroup negation character */
X#define DEADTIME 45 /* no. of seconds to wait on deadlock */
X#define FMETA '%' /* file meta-character for c option */
X#ifdef pdp11
X# define BUFLEN 128 /* standard buffer size */
X#else
X# define BUFLEN 256 /* standard buffer size */
X#endif
X#define LBUFLEN 1024 /* big buffer size */
X#define SYSPATH "PATH=/local/bin:/bin:/usr/bin" /* default, secure, vanilla path */
X#define LNCNT 16 /* Articles with > LNCNT lines go through pager */
X
X/* Things you probably won't want to change */
X#define PATHLEN 512 /* length of longest source string */
X#define DATELEN 64 /* length of longest allowed date string */
X#define NAMELEN 64 /* length of longest possible message ID */
X#define SNLN 8 /* max significant characters in sysname */
X#define PROTO 'A' /* old protocol name */
X#define NETCHRS "!:.@^%"/* Punct. chars used for various networks */
X#define TRUE 1 /* boolean true */
X#define FALSE 0 /* boolean false */
X#define AFSIZ 5000 /* legal newsgroup file size */
X#define NGDELIM ',' /* delimit character in news group line */
*-*-END-of-src/defs.dist-*-*
echo x - src/digest.c
sed 's/^X//' >src/digest.c <<'*-*-END-of-src/digest.c-*-*'
X/*
X * digest - process ARPANET digests
X *
X * Alan Hastings 9/5/82
X *
X * digest(ifile, ofile, header)
X * FILE *ifile, *ofile;
X * struct header *header;
X *
X * returns: TRUE EOF reached, exit from readnews.
X * FALSE normal exit, continue reading news.
X */
X
Xstatic char *Sccsid = "@(#)digest.c 1.3 4/20/84";
X
X#include "rparams.h"
X
Xstruct art {
X long a_hdr;
X long a_bod;
X int a_blen;
X int a_hlen;
X};
X
X#define loop for(;;)
X#define getnum(p, n) for (n=0; *p>='0' && *p<='9'; p++) n = n*10 + *p-'0'
X#define errchk(p) if (*p) goto badopt
X
X#define MAXART 128
X
Xstruct art *arts;
Xint lastart;
X
Xdigest(ifp, ofp, h)
XFILE *ifp, *ofp;
Xstruct hbuf *h;
X{
X register int n, curart;
X struct art artbuf[MAXART];
X int printh, eod, nomore;
X char cbuf[BUFLEN], *cmd;
X
X arts = artbuf;
X printh = TRUE;
X nomore = eod = FALSE;
X curart = 1;
X
X if (dscan(ifp))
X return(FALSE);
X
X dprint(0, ifp, ofp);
X
X loop {
X if (nomore) break;
X if (curart < 1) {
X curart = 1;
X eod = nomore = FALSE;
X }
X if (curart > lastart) curart = lastart;
X if (eod) nomore = TRUE;
X if (printh && !nomore)
X (void) dhprint(curart, ifp, ofp);
X getcmd:
X loop {
X sigtrap = FALSE;
X fprintf(ofp, "Digest article %d of %d ", curart, lastart);
X if (curart==lastart && nomore)
X fprintf(ofp, "Last digest article ");
X fprintf(ofp, "(%d lines) More? [%s] ",
X arts[curart].a_blen, nomore?"snq":"ynq");
X (void) fflush(ofp);
X cmd = cbuf;
X if (fgets(cmd, BUFLEN, stdin))
X break;
X if (!sigtrap)
X return(TRUE);
X putc('\n', ofp);
X }
X nstrip(cmd);
X while (*cmd==' ' || *cmd=='\t')
X cmd++;
X printh = TRUE;
X
X switch (*cmd++) {
X case '#':
X fprintf(ofp, "%d articles in digest\n", lastart);
X (void) fflush(ofp);
X printh = FALSE;
X break;
X
X case '$':
X curart = lastart;
X break;
X
X case '!':
X fwait(fsubr(ushell, cmd, (char *)NULL));
X fprintf(ofp, "!\n");
X printh = FALSE;
X break;
X
X case '\0':
X if (nomore) {
X putc('\n', ofp);
X return(FALSE);
X }
X cmd--;
X case 'y':
X case 'p':
X errchk(cmd);
X dprint(curart++, ifp, ofp);
X if (curart > lastart)
X eod = TRUE;
X break;
X
X case 'n':
X errchk(cmd);
X if (++curart > lastart) {
X putc('\n', ofp);
X return(FALSE);
X }
X break;
X
X case '+':
X getnum(cmd, n);
X errchk(cmd);
X if (nomore) {
X putc('\n', ofp);
X return(FALSE);
X }
X if (n) curart += n;
X else {
X curart += 1;
X if (curart > lastart)
X eod = TRUE;
X }
X break;
X
X case '-':
X getnum(cmd, n);
X errchk(cmd);
X eod = nomore = FALSE;
X curart -= (n) ? n : 1;
X break;
X
X case '0': case '1': case '2': case '3': case '4':
X case '5': case '6': case '7': case '8': case '9':
X cmd--;
X getnum(cmd, n);
X errchk(cmd);
X curart = n;
X eod = nomore = FALSE;
X break;
X
X case 'q':
X case 'x':
X putc('\n', ofp);
X return(FALSE);
X
X case '?':
X fprintf(ofp, "\nDigester options:\n\n");
X fprintf(ofp, "y\tyes, print article.\n");
X fprintf(ofp, "n\tno, go to next article.\n");
X fprintf(ofp, "q\texit from digester.\n");
X fprintf(ofp, "h\tprint article header.\n");
X fprintf(ofp, "s file\tsave article in file.\n");
X fprintf(ofp, "t\ttable of contents.\n");
X fprintf(ofp, "+[n]\tforward n articles (1).\n");
X fprintf(ofp, "-[n]\tback n articles (1).\n");
X fprintf(ofp, "\nh and s may be followed by '-'\n");
X (void) fflush(ofp);
X break;
X
X case 'h':
X n = curart;
X if (*cmd=='-') {
X cmd++;
X if (n > 1) n--;
X }
X errchk(cmd);
X (void) dhprint(n, ifp, ofp);
X nomore = printh = FALSE;
X if (n!=curart)
X putc('\n', ofp);
X break;
X
X case 's':
X case 'w':
X n = curart;
X if (*cmd=='-') {
X cmd++;
X if (n > 1) n--;
X }
X while (*cmd==' ' || *cmd=='\t')
X cmd++;
X dsaveart(n, ifp, ofp, cmd);
X nomore = printh = FALSE;
X if (n!=curart)
X putc('\n', ofp);
X break;
X
X case 'H':
X errchk(cmd);
X hprint(h, ofp, 1);
X eod = nomore = FALSE;
X break;
X
X case 'T':
X case 't':
X errchk(cmd);
X if (cmd[-1]=='T')
X hprint(h, ofp, 0);
X dprint(0, ifp, ofp);
X eod = nomore = FALSE;
X break;
X
X default:
X badopt:
X if (!nomore)
X fprintf(ofp, "y (yes), n (no), ");
X fprintf(ofp, "q (quit), s file (save), h (header), t (table of contents)\n");
X fprintf(ofp, "? for help\n");
X goto getcmd;
X }
X }
X putc('\n', ofp);
X return(FALSE);
X}
X
Xdscan(ifp)
Xregister FILE *ifp;
X{
X char scanbuf[BUFLEN];
X register int n, len;
X register char *s;
X register long pos;
X short wasblank;
X
X n = len = 0;
X wasblank = FALSE;
X s = scanbuf;
X arts[0].a_bod = arts[1].a_hdr = ftell(ifp);
X arts[0].a_hdr = 0L;
X arts[1].a_bod = -1L;
X
X loop {
X if (sigtrap)
X return(TRUE);
X pos = ftell(ifp);
X if (fgets(s, BUFLEN, ifp)==NULL)
X *s = '\0';
X if (wasblank && isheader(s)) {
X long lastpos;
X short isblank;
X short nhlines;
X arts[n++].a_blen = len;
X len = 0;
X nhlines = 0;
X arts[n].a_hdr = pos;
X isblank = FALSE;
X do {
X lastpos = pos;
X wasblank = isblank;
X nhlines++;
X pos = ftell(ifp);
X if (fgets(s, BUFLEN, ifp)==NULL)
X *s = '\0';
X else
X len++;
X isblank = (*s=='\n') ? TRUE : FALSE;
X if (isblank && nhlines==1)
X /* one liner--not a header */
X break;
X } while ((isblank && !wasblank) || isheader(s));
X if ((!isblank && !wasblank) || nhlines < 2) {
X /* oops! not a header... back off */
X arts[n].a_hdr = arts[n-1].a_bod;
X len += arts[--n].a_blen;
X } else {
X if (wasblank)
X pos = lastpos;
X arts[n].a_hlen = len;
X arts[n].a_bod = arts[n+1].a_hdr = pos;
X arts[n+1].a_bod = -1L;
X arts[n+1].a_hlen = 3; /* average header len */
X len = 0;
X }
X }
X if (*s=='\0')
X break;
X wasblank = (*s=='\n') ? TRUE : FALSE;
X len++;
X }
X arts[n].a_blen = len;
X arts[n+1].a_hdr = pos;
X lastart = n;
X return(FALSE);
X}
X
Xdhprint(art, ifp, ofp)
Xregister int art;
Xregister FILE *ifp, *ofp;
X{
X register char c;
X register long pos = arts[art].a_hdr;
X register long epos = arts[art].a_bod;
X register int nlines = 1;
X
X putc('\n', ofp);
X fseek(ifp, pos, 0);
X while (pos++ < epos && !sigtrap) {
X if ((c = getc(ifp))=='\n')
X nlines++;
X putc(c, ofp);
X }
X (void) fflush(ofp);
X sigtrap = FALSE;
X return(nlines);
X}
X
Xdprint(art, ifp, ofp)
Xint art;
XFILE *ifp, *ofp;
X{
X#ifdef PAGE
X register int cnt;
X FILE *pfp, *popen();
X
X if (art && arts[art].a_blen > 23-arts[art+1].a_hlen && *PAGER) {
X if (!index(PAGER, FMETA)) {
X if ((pfp = popen(PAGER, "w"))==NULL)
X (void) dprinta(art, ifp, ofp);
X else {
X cnt = dprinta(art, ifp, pfp) % 23;
X if (cnt > 23-arts[art+1].a_hlen)
X while (cnt++ < 24)
X putc('\n', pfp);
X (void) pclose(pfp);
X }
X } else
X pout(ofp);
X } else
X#endif PAGE
X (void) dprinta(art, ifp, ofp);
X}
X
Xdprinta(art, ifp, ofp)
Xint art;
Xregister FILE *ifp, *ofp;
X{
X register char c;
X register long pos = arts[art].a_bod;
X register long epos = arts[art+1].a_hdr;
X register int nlines = 0;
X
X fseek(ifp, pos, 0);
X while (pos++ < epos && !sigtrap) {
X if ((c = getc(ifp))=='\n')
X nlines++;
X putc(c, ofp);
X }
X (void) fflush(ofp);
X sigtrap = FALSE;
X return(nlines);
X}
X
Xdsaveart(art, ifp, ofp, name)
Xint art;
Xregister FILE *ifp, *ofp;
Xregister char *name;
X{
X register FILE *nfp;
X char fname[BUFLEN];
X char *strcat(), *strcpy(), *getenv();
X register char *nb;
X
X while (*name==' ' || *name=='\t')
X name++;
X
X if (*name=='|') {
X fprintf(ofp, "don't know how to pipe yet.\n");
X (void) fflush(ofp);
X return;
X } else if (*name=='/')
X (void) strcpy(fname, name);
X else {
X if (nb = getenv("NEWSBOX"))
X (void) strcpy(fname, nb);
X else
X (void) strcpy(fname, userhome);
X (void) strcat(fname, "/");
X (void) strcat(fname, name);
X }
X
X fprintf(ofp, "Save digest article %d in \"%s\"", art, fname);
X (void) fflush(ofp);
X if ((nfp = fopen(fname, "a"))!=NULL) {
X int ln;
X ln = dhprint(art, ifp, nfp);
X ln += dprinta(art, ifp, nfp);
X fprintf(ofp, " [Appended] %d lines\n", ln);
X (void) fclose(nfp);
X } else
X fprintf(ofp, " cannot append to.\n");
X}
X
Xisheader(s)
Xregister char *s;
X{
X if (isupper(*s) || islower(*s)) {
X while (*s && *s!=':' && !isspace(*s))
X s++;
X if (*s==':' && *++s==' ')
X return(TRUE);
X }
X return(FALSE);
X}
*-*-END-of-src/digest.c-*-*
echo x - src/expire.c
sed 's/^X//' >src/expire.c <<'*-*-END-of-src/expire.c-*-*'
X/*
X * expire - expire daemon runs around and nails all articles that
X * have expired.
X *
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)expire.c 2.31 9/3/84";
X#endif lint
X
X#include "params.h"
X#include <errno.h>
X#if defined(BSD4_2) || defined(BSD4_1C)
X# include <sys/dir.h>
X#else
X# include "ndir.h"
X#endif
X
Xchar *Progname = "expire"; /* used by xerror to identify failing program */
X
X/* Number of array entries to allocate at a time. */
X#define SPACE_INCREMENT 1000
X
Xextern char groupdir[BUFSIZ], rcbuf[BUFLEN];
Xextern int errno;
Xchar NARTFILE[BUFSIZ], OARTFILE[BUFSIZ];
Xchar PAGFILE[BUFLEN], DIRFILE[BUFLEN];
Xchar NACTIVE[BUFSIZ], OACTIVE[BUFSIZ];
Xextern char *OLDNEWS;
Xint verbose = 0;
Xint ignorexp = 0;
Xint doarchive = 0;
Xint nohistory = 0;
Xint dorebuild = 0;
Xint usepost = 0;
Xint frflag = 0;
Xint updateactive = 0;
Xchar baduser[BUFLEN], filename[BUFLEN];
X
X/*
X * This code uses realloc to get more of the multhist array.
X */
Xstruct multhist {
X char *mh_ident;
X char *mh_file;
X} *multhist;
Xunsigned int mh_size;
Xchar *calloc();
Xchar *realloc();
X
Xtypedef struct {
X char *dptr;
X int dsize;
X} datum;
X
Xlong expincr;
Xlong atol();
Xtime_t cgtdate(), time();
XFILE *popen();
Xstruct passwd *pw;
Xstruct group *gp;
Xchar arpat[LBUFLEN];
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X register FILE *fp = NULL;
X struct hbuf h;
X register time_t now, newtime;
X char ngpat[LBUFLEN];
X char afline[BUFLEN];
X char *p1, *p2, *p3;
X FILE *ohfd, *nhfd;
X DIR *ngdirp;
X static struct direct *ngdir;
X char fn[BUFLEN];
X int uid, gid, duid, dgid;
X int i;
X
X pathinit();
X umask(N_UMASK);
X
X uid = getuid();
X gid = getgid();
X duid = geteuid();
X dgid = getegid();
X if (uid == 0 && geteuid() == 0) {
X /*
X * Must go through with this kludge since
X * some systems do not honor the setuid bit
X * when root invokes a setuid program.
X */
X if ((pw = getpwnam(NEWSUSR)) == NULL)
X xerror("Cannot get NEWSUSR pw entry");
X
X duid = pw->pw_uid;
X if ((gp = getgrnam(NEWSGRP)) == NULL)
X xerror("Cannot get NEWSGRP gr entry");
X dgid = gp->gr_gid;
X setuid(duid);
X setgid(dgid);
X }
X
X expincr = DFLTEXP;
X ngpat[0] = '\0';
X while (argc > 1) {
X switch (argv[1][1]) {
X case 'v':
X if (isdigit(argv[1][2]))
X verbose = argv[1][2] - '0';
X else if (argc > 2 && argv[2][0] != '-') {
X
X argv++;
X argc--;
X verbose = atoi(argv[1]);
X } else
X verbose = 1;
X if (verbose < 3)
X setbuf(stdout, (char *)NULL);
X break;
X case 'e': /* Use this as default expiration time */
X if (argc > 2 && argv[2][0] != '-') {
X argv++;
X argc--;
X expincr = atol(argv[1]) * DAYS;
X } else if (isdigit(argv[1][2]))
X expincr = atol(&argv[1][2]) * DAYS;
X break;
X case 'I': /* Ignore any existing expiration date */
X ignorexp = 2;
X break;
X case 'i': /* Ignore any existing expiration date */
X ignorexp = 1;
X break;
X case 'n':
X if (argc > 2) {
X argv++;
X argc--;
X while (argc > 1 && argv[1][0] != '-') {
X strcat(ngpat, argv[1]);
X ngcat(ngpat);
X argv++;
X argc--;
X }
X argv--;
X argc++;
X }
X break;
X case 'a': /* archive expired articles */
X if (access(OLDNEWS,0) < 0 ){
X perror(OLDNEWS);
X fprintf(stderr,"No archiving possible\n");
X xxit(1);
X }
X doarchive++;
X if (argc > 2) {
X argv++;
X argc--;
X while (argc > 1 && argv[1][0] != '-') {
X strcat(arpat, argv[1]);
X ngcat(arpat);
X argv++;
X argc--;
X }
X argv--;
X argc++;
X }
X break;
X case 'h': /* ignore history */
X nohistory++;
X break;
X case 'r': /* rebuild history file */
X dorebuild++;
X nohistory++;
X break;
X case 'p':
X usepost++;
X break;
X case 'f':
X frflag++;
X if (argc > 2) {
X strcpy(baduser, argv[2]);
X argv++;
X argc--;
X }
X break;
X case 'u':
X updateactive++;
X break;
X default:
X printf("Usage: expire [ -v [level] ] [-e days ] [-i] [-a] [-r] [-h] [-p] [-u] [-f username] [-n newsgroups]\n");
X xxit(1);
X }
X argc--;
X argv++;
X }
X if (ngpat[0] == 0)
X strcpy(ngpat, "all,");
X if (arpat[0] == 0)
X strcpy(arpat, "all,");
X now = time((time_t)0);
X if (chdir(SPOOL))
X xerror("Cannot chdir %s", SPOOL);
X
X if (verbose) {
X printf("expire: nohistory %d, rebuild %d, doarchive %d\n",
X nohistory, dorebuild, doarchive);
X printf("newsgroups: %s\n",ngpat);
X if (doarchive)
X printf("archiving: %s\n",arpat);
X }
X
X sprintf(OARTFILE, "%s/%s", LIB, "ohistory");
X sprintf(NARTFILE, "%s/%s", LIB, "nhistory");
X
X sprintf(OACTIVE, "%s/%s", LIB, "oactive");
X sprintf(NACTIVE, "%s/%s", LIB, "nactive");
X
X if (updateactive)
X goto doupdateactive;
X
X#ifdef DBM
X if (!dorebuild)
X {
X sprintf(PAGFILE, "%s/%s", LIB, "nhistory.pag");
X sprintf(DIRFILE, "%s/%s", LIB, "nhistory.dir");
X close(creat(PAGFILE, 0666));
X close(creat(DIRFILE, 0666));
X dbminit(NARTFILE);
X }
X#endif
X
X if (nohistory) {
X ohfd = xfopen(ACTIVE, "r");
X if (dorebuild) {
X /* Allocate initial space for multiple newsgroup (for an
X article) array */
X multhist = (struct multhist *)
X calloc (SPACE_INCREMENT,
X sizeof (struct multhist));
X mh_size = SPACE_INCREMENT;
X
X sprintf(afline, "sort -t\t +1 >%s", NARTFILE);
X if ((nhfd = popen(afline, "w")) == NULL)
X xerror("Cannot exec %s", NARTFILE);
X } else
X nhfd = xfopen("/dev/null", "w");
X } else {
X ohfd = xfopen(ARTFILE, "r");
X nhfd = xfopen(NARTFILE, "w");
X }
X
X for(i=0;i<NUNREC;i++)
X h.unrec[i] = NULL;
X
X while (TRUE) {
X if (nohistory) {
X do {
X if (ngdir == NULL) {
X if ( ngdirp != NULL )
X closedir(ngdirp);
X if (fgets(afline, BUFLEN, ohfd) == NULL)
X goto out;
X strcpy(groupdir, afline);
X p1 = index(groupdir, ' ');
X if (p1 == NULL)
X p1 = index(groupdir, '\n');
X if (p1 != NULL)
X *p1 = NULL;
X if (!ngmatch(groupdir, ngpat))
X continue;
X
X /* Change a group name from
X a.b.c to a/b/c */
X for (p1=groupdir; *p1; p1++)
X if (*p1 == '.')
X *p1 = '/';
X
X if ((ngdirp = opendir(groupdir)) == NULL)
X continue;
X
X }
X ngdir = readdir(ngdirp);
X /* Continue looking if not an article. */
X } while ( ngdir == NULL || !islegal(fn,groupdir,ngdir->d_name));
X
X p2 = fn;
X if (verbose > 2)
X printf("article: %s\n", fn);
X } else {
X if (fgets(afline, BUFLEN, ohfd) == NULL)
X break;
X if (verbose > 2)
X printf("article: %s", afline);
X p1 = index(afline, '\t');
X if (p1)
X p2 = index(p1 + 1, '\t');
X else
X continue;
X if (!p2)
X continue;
X p2++;
X strcpy(groupdir, p2);
X p3 = index(groupdir, '/');
X if (p3)
X *p3 = 0;
X else {
X /*
X * Nothing after the 2nd tab. This happens
X * when a control message is stored in the
X * history file. Use the date in the history
X * file to decide expiration.
X */
X h.expdate[0] = 0;
X strcpy(h.recdate, p1+1);
X goto checkdate;
X }
X if (!ngmatch(groupdir, ngpat)) {
X fputs(afline, nhfd);
X *p1 = 0;
X remember(afline);
X continue;
X }
X strcpy(fn, p2);
X p1 = index(fn, ' ');
X if (p1 == 0)
X p1 = index(fn, '\n');
X if (p1)
X *p1 = 0;
X }
X
X strcpy(filename, dirname(fn));
X if (access(filename, 4)
X || (fp = fopen(filename, "r")) == NULL) {
X if (verbose)
X printf("Can't open %s.\n", filename);
X continue;
X }
X for(i=0;i<NUNREC;i++)
X if (h.unrec[i] != NULL)
X free(h.unrec[i]);
X else
X break;
X if (hread(&h, fp, TRUE) == NULL) {
X printf("Garbled article %s.\n", filename);
X fclose(fp);
X continue;
X }
X if (dorebuild) {
X register char *cp;
X register struct multhist *mhp;
X
X /* Format of filename until now was /SPOOL/a/b/c.4
X and this code changes it to a.b.c/4 (the correct
X kind of entry in the history file. */
X strcpy (filename, filename + strlen(SPOOL)+1);
X for (p1 = filename; p1 != NULL && *p1 != '\0'; p1++)
X if (*p1 == '/' && p1 != rindex (p1, '/'))
X *p1 = '.';
X
X if ((cp = index(h.nbuf, NGDELIM)) == NULL) {
Xsaveit:
X fprintf(nhfd, "%s\t%s\t%s \n", h.ident, h.recdate, filename);
X fclose(fp);
X continue;
X }
X for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++) {
X if (mhp->mh_file == NULL)
X continue;
X if (strcmp(mhp->mh_ident, h.ident) != 0)
X continue;
X if (index(mhp->mh_file, ' ') != NULL)
X cp = index(++cp, NGDELIM);
X strcat(filename, " ");
X strcat(filename, mhp->mh_file);
X free(mhp->mh_file);
X mhp->mh_file = NULL;
X if (*cp == NULL || (cp = index(++cp, NGDELIM)) == NULL)
X goto saveit;
X else
X break;
X }
X
X /* Here is where we realloc the multhist space rather
X than the old way of static allocation. It's
X really trivial. We just clear out the space
X in case it was reused. The old static array was
X guaranteed to be cleared since it was cleared when
X the process started. */
X if (mhp >= multhist + mh_size) {
X multhist = (struct multhist *)
X realloc (multhist,
X sizeof (struct multhist) *
X (SPACE_INCREMENT + mh_size));
X if (multhist == NULL)
X xerror("Too many articles with multiple newsgroups");
X for (mhp = multhist + mh_size;
X mhp < multhist+mh_size+SPACE_INCREMENT;
X mhp++) {
X mhp->mh_ident = NULL;
X mhp->mh_file = NULL;
X }
X mhp = multhist + mh_size;
X mh_size += SPACE_INCREMENT;
X }
X
X mhp->mh_ident = malloc(strlen(h.ident)+1);
X strcpy(mhp->mh_ident, h.ident);
X cp = malloc(strlen(filename) + 1);
X if ( cp == NULL)
X xerror("Out of memory");
X strcpy(cp, filename);
X mhp->mh_file = cp;
X fclose(fp);
X continue;
X }
X
X fclose(fp);
Xcheckdate:
X if (h.expdate[0])
X h.exptime = cgtdate(h.expdate);
X newtime = cgtdate(usepost ? h.subdate : h.recdate) + expincr;
X if (!h.expdate[0] || ignorexp == 2 ||
X (ignorexp == 1 && newtime < h.exptime))
X h.exptime = newtime;
X if (frflag ? strcmp(baduser,h.from)==0 : now >= h.exptime) {
X#ifdef DEBUG
X printf("cancel %s\n", filename);
X#else
X if (verbose)
X printf("cancel %s\n", filename);
X ulall(p2, &h);
X#endif
X } else {
X fputs(afline, nhfd);
X if (!dorebuild)
X remember(h.ident);
X if (verbose > 2)
X printf("Good article %s\n", rcbuf);
X }
X }
X
Xout:
X if (dorebuild) {
X register struct multhist *mhp;
X for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++)
X /* should "never" happen */
X if (mhp->mh_file != NULL ) {
X printf("Article: %s %s Cannot find all links\n", mhp->mh_ident, mhp->mh_file);
X sprintf(filename,"%s/%s",SPOOL,mhp->mh_file);
X for (p1 = filename; *p1 != ' ' && *p1 != '\0'; p1++)
X if (*p1 == '.')
X *p1 = '/';
X *p1 = '\0';
X if ((fp = fopen(filename, "r")) == NULL) {
X if (verbose)
X printf("Can't open %s.\n", filename);
X continue;
X }
X for(i=0;i<NUNREC;i++)
X if (h.unrec[i] != NULL)
X free(h.unrec[i]);
X else
X break;
X if (hread(&h, fp, TRUE) == NULL) {
X printf("Garbled article %s.\n", filename);
X fclose(fp);
X continue;
X }
X
X fprintf(nhfd, "%s\t%s\t%s \n", h.ident, h.recdate, mhp->mh_file);
X fclose(fp);
X continue;
X }
X pclose(nhfd);
X free (multhist);
X }
X
X if (dorebuild || !nohistory) {
X rename(ARTFILE, OARTFILE);
X rename(NARTFILE, ARTFILE);
X#ifdef DBM
X if (dorebuild)
X rebuilddbm ( );
X else
X {
X char bfr[BUFLEN];
X sprintf(bfr,"%s.pag", ARTFILE);
X strcat(OARTFILE, ".pag");
X strcat(NARTFILE, ".pag");
X rename(bfr, OARTFILE);
X rename(NARTFILE, bfr);
X sprintf(bfr,"%s.dir", ARTFILE);
X strcpy(rindex(OARTFILE, '.'), ".dir");
X strcpy(rindex(NARTFILE, '.'), ".dir");
X rename(bfr, OARTFILE);
X rename(NARTFILE, bfr);
X }
X#endif
X }
X
Xdoupdateactive:
X ohfd = xfopen(ACTIVE, "r");
X nhfd = xfopen(NACTIVE, "w");
X do {
X long n;
X long maxart, minart;
X char cansub;
X int gdsize;
X struct stat stbuf;
X
X if (fgets(afline, BUFLEN, ohfd) == NULL)
X continue;
X if (sscanf(afline,"%s %ld %ld %c",groupdir,&maxart, &minart,
X &cansub) < 4)
X xerror("Active file corrupt");
X minart = maxart > 0 ? maxart : 1L;
X /* Change a group name from
X a.b.c to a/b/c */
X for (p1=groupdir; *p1; p1++)
X if (*p1 == '.')
X *p1 = '/';
X
X gdsize = strlen(groupdir);
X if ((ngdirp = opendir(groupdir)) != NULL) {
X while (ngdir = readdir(ngdirp)) {
X groupdir[gdsize] = '/';
X strcpy(&groupdir[gdsize+1],ngdir->d_name);
X /* We have to do a stat because of micro.6809 */
X if (stat(groupdir,&stbuf) < 0 ||
X !(stbuf.st_mode&S_IFREG) )
X continue;
X n = atol(ngdir->d_name);
X if (n > 0 && n < minart)
X minart = n;
X if (n > 0 && n > maxart)
X maxart = n;
X }
X closedir(ngdirp);
X }
X afline[gdsize] = '\0';
X fprintf(nhfd,"%s %05ld %05ld %c\n", afline, maxart, minart, cansub);
X } while ( !feof(ohfd));
X fclose(nhfd);
X fclose(ohfd);
X
X rename(ACTIVE, OACTIVE);
X rename(NACTIVE, ACTIVE);
X
X xxit(0);
X}
X
X/* Unlink (using tail recursion) all the articles in 'artlist'. */
Xulall(artlist, h)
Xchar *artlist;
Xstruct hbuf *h;
X{
X register char *p, *q;
X int last = 0;
X char newname[BUFLEN];
X time_t timep[2];
X char *fn;
X
X if (verbose > 2)
X printf("ulall '%s', '%s'\n", artlist, h->subdate);
X if (nohistory) {
X last = 1;
X } else {
X while (*artlist == ' ' || *artlist == '\n' || *artlist == ',')
X artlist++;
X if (*artlist == 0)
X return;
X p = index(artlist, ' ');
X if (p == 0) {
X last = 1;
X p = index(artlist, '\n');
X }
X if (p == 0) {
X last = 1;
X p = index(artlist, ',');
X }
X if (p == 0) {
X last = 1;
X fn = dirname(artlist);
X unlink(fn);
X return;
X }
X if (p)
X *p = 0;
X }
X fn = dirname(artlist);
X if (doarchive){
X strcpy(newname, artlist);
X q = index(newname,'/');
X if (q) {
X *q++ = NGDELIM;
X *q = '\0';
X }
X if (ngmatch(newname, arpat)) {
X q = fn + strlen(SPOOL) + 1;
X sprintf(newname, "%s/%s", OLDNEWS, q);
X if (verbose)
X printf("link %s to %s\n", fn, newname);
X if (link(fn, newname) == -1) {
X if (mkparents(newname) == 0)
X if (link(fn, newname) == -1)
X fcopy(fn, newname);
X }
X timep[0] = timep[1] = cgtdate(h->subdate);
X utime(newname, timep);
X }
X }
X if (verbose)
X printf("unlink %s\n", fn);
X unlink(fn);
X if (!last)
X ulall(p + 1, h);
X}
X
Xfcopy(fn, newname)
Xchar *fn, *newname;
X{
X int f1, f2;
X int r;
X char buf[BUFSIZ];
X f1 = open(fn, 0);
X if (f1 < 0)
X return -1;
X f2 = open(newname, 1);
X if (f2 < 0) {
X if (errno == ENOENT) {
X f2 = creat(newname,0644);
X if (f2 < 0)
X return -1;
X } else
X return -1;
X }
X while((r=read(f1, buf, BUFSIZ)) > 0)
X write(f2, buf, r);
X close(f1);
X close(f2);
X return 0;
X}
X
X/*
X * If any parent directories of this dir don't exist, create them.
X */
Xmkparents(dirname)
Xchar *dirname;
X{
X char buf[200], sysbuf[200];
X register char *p;
X int rc;
X struct passwd *pw;
X
X strcpy(buf, dirname);
X p = rindex(buf, '/');
X if (p)
X *p = '\0';
X if (access(buf,0) == 0)
X return 0;
X mkparents(buf);
X sprintf(sysbuf, "mkdir %s", buf);
X rc = system(sysbuf);
X sprintf(sysbuf, "%s", buf);
X if (verbose)
X printf("mkdir %s, rc %d\n", sysbuf, rc);
X chmod(sysbuf, 0755);
X chown(sysbuf, duid, dgid);
X
X return rc;
X}
X
X
X/* Make sure this file is a legal article. */
Xislegal(fullname, path, name)
X register char *fullname;
X register char *path;
X register char *name;
X{
X struct stat buffer;
X
X sprintf(fullname, "%s/%s", path, name);
X
X /* make sure the article is numeric. */
X while (*name != '\0')
X if (!isascii(*name) || !isdigit(*name))
X return 0;
X else
X name++;
X
X /* Now make sure we don't have a group like net.micro.432,
X * which is numeric but not a regular file -- i.e., check
X * for being a regular file.
X */
X if ((stat(fullname, &buffer) == 0) &&
X ((buffer.st_mode & S_IFMT) == S_IFREG)) {
X /* Now that we found a legal group in a/b/c/4
X notation, switch it to a.b.c/4 notation. */
X for (name = fullname; name != NULL && *name != '\0'; name++)
X if (*name == '/' && name != rindex (name, '/'))
X *name = '.';
X
X return 1;
X }
X return 0;
X}
X
X#ifdef DBM
X/*
X * This is taken mostly intact from ../cvt/cvt.hist.c and is used at the
X * end by the options that make a new history file.
X * Routine to convert history file to dbm file. The old 3 field
X * history file is still kept there, because we need it for expire
X * and for a human readable copy. But we keep a dbm hashed copy
X * around by message ID so we can answer the yes/no question "have
X * we already seen this message". The content is the ftell offset
X * into the real history file when we get the article - you can't
X * really do much with this because the file gets compacted.
X */
X
XFILE *fd;
X
Xchar namebuf[BUFSIZ];
Xchar lb[BUFSIZ];
X
Xrebuilddbm( )
X{
X register char *p;
X long fpos;
X datum lhs, rhs;
X
X umask(0);
X sprintf(namebuf, "%s.dir", ARTFILE);
X close(creat(namebuf, 0666));
X sprintf(namebuf, "%s.pag", ARTFILE);
X close(creat(namebuf, 0666));
X sprintf(namebuf, "%s", ARTFILE);
X
X fd = fopen(namebuf, "r");
X if (fd == NULL) {
X perror(namebuf);
X xxit(2);
X }
X
X dbminit(namebuf);
X while (fpos=ftell(fd), fgets(lb, BUFSIZ, fd) != NULL) {
X p = index(lb, '\t');
X if (p)
X *p = 0;
X p = lb;
X while (*++p)
X if (isupper(*p))
X *p = tolower(*p);
X lhs.dptr = lb;
X lhs.dsize = strlen(lb) + 1;
X rhs.dptr = (char *) &fpos;
X rhs.dsize = sizeof fpos;
X if (store(lhs, rhs) < 0)
X fprintf(stderr, "store(%s) failed\n", lb);
X }
X}
X#endif DBM
X
Xremember(article)
X char *article;
X{
X static long number;
X register char *rcp;
X datum lhs, rhs;
X
X#ifdef DBM
X strcpy(lb, article);
X rcp = lb;
X while (*++rcp)
X if (isupper(*rcp))
X *rcp = tolower(*rcp);
X lhs.dptr = lb;
X lhs.dsize = strlen(lb)+1;
X
X number++;
X
X rhs.dptr = (char *) &number;
X rhs.dsize = sizeof(number);
X
X store(lhs, rhs);
X#endif
X}
X
X#if !defined(BSD4_2) && !defined(BSD4_1C)
Xrename(from,to)
Xregister char *from, *to;
X{
X unlink(to);
X if (link(from, to) < 0)
X return -1;
X
X unlink(from);
X return 0;
X}
X#endif !BSD4_2 && ! BSD4_1C
X
Xxxit(i)
X{
X exit(i);
X}
*-*-END-of-src/expire.c-*-*
echo x - src/ftime.c
sed 's/^X//' >src/ftime.c <<'*-*-END-of-src/ftime.c-*-*'
Xstatic char *SccsId = "@(#)ftime.c 2.4 4/20/84";
X
X#include <sys/types.h>
Xstruct timeb
X{
X time_t time;
X unsigned short millitm;
X short timezone;
X short dstflag;
X};
X
Xextern long timezone;
Xextern int daylight;
X
Xftime(tp)
Xstruct timeb *tp;
X{
X long t;
X
X time(&t);
X tp->time = t;
X tp->millitm = 0;
X tp->timezone = timezone/60;
X tp->dstflag = daylight;
X}
*-*-END-of-src/ftime.c-*-*
echo x - src/fullname.c
sed 's/^X//' >src/fullname.c <<'*-*-END-of-src/fullname.c-*-*'
X/*
X * fullname.c - this file is made separate so that different local
X * conventions can be applied. The stock version understands two
X * conventions:
X *
X * (a) Berkeley finger: the gecos field in /etc/passwd begins with
X * the full name, terminated with comma, semicolon, or end of
X * field. & expands to the login name.
X * (b) BTL RJE: the gecos field looks like
X * : junk - full name ( junk :
X * where the "junk -" is optional.
X *
X * If you have a different local convention, modify this file accordingly.
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)fullname.c 1.7 8/14/84";
X#endif !lint
X
X#include <stdio.h>
X#include <ctype.h>
X#include <pwd.h>
X#ifdef USG
Xstruct passwd *getpwent(), *getpwuid(), *getpwnam();
X#endif USG
X#include "defs.h"
X
X#ifndef LOCALNAME
X/*
X * Figure out who is sending the message and sign it.
X * We attempt to look up the user in the gecos field of /etc/passwd.
X */
Xchar *
Xfullname(un)
Xchar *un;
X{
X static char inbuf[100];
X struct passwd *pw;
X
X pw = getpwnam(un);
X if (pw == NULL)
X return un;
X buildfname(pw->pw_gecos, un, inbuf);
X if (inbuf[0] == 0)
X return un;
X return inbuf;
X}
X
X#else
X
X/*
X * Alternative version of fullname which asks the user for his full name.
X * This is mainly suitable for systems that don't have a full name
X * database somewhere. It puts the answer in $HOME/.name
X */
Xchar *
Xfullname(un)
Xchar *un;
X{
X static char inbuf[100];
X char fbuf[100];
X FILE *fd;
X char *p, *index(), *getenv();
X int pid;
X
X if (!isatty(2))
X return un;
X printf("What is your full name (for news article signatures): ");
X fflush(stdout);
X read(2, inbuf, sizeof inbuf);
X if (inbuf[0] == 0)
X return un;
X p = index(inbuf, '\n');
X if (p)
X *p = 0;
X if ((p = getenv("HOME")) == NULL) {
X fprintf(stderr,
X "inews: no HOME environment variable - .name not written\n");
X return inbuf;
X }
X sprintf(fbuf, "%s/%s", p, ".name");
X if ((pid = fork()) < 0) {
X perror("inews");
X return inbuf;
X }
X else if (pid != 0)
X while (wait((int *)0) != pid)
X ;
X else {
X setuid(getuid()); /* become the user */
X if ((fd = fopen(fbuf, "w")) == NULL)
X fprintf(stderr, "inews: can't create %s\n", fbuf);
X else {
X fprintf(fd, "%s\n", inbuf);
X fclose(fd);
X }
X exit(0);
X }
X return inbuf;
X}
X#endif
X
X#ifndef LOCALNAME
X/*
X** BUILDFNAME -- build full name from gecos style entry.
X** (routine lifted from sendmail)
X**
X** This routine interprets the strange entry that would appear
X** in the GECOS field of the password file.
X**
X** Parameters:
X** p -- name to build.
X** login -- the login name of this user (for &).
X** buf -- place to put the result.
X**
X** Returns:
X** none.
X**
X** Side Effects:
X** none.
X*/
X
Xbuildfname(p, login, buf)
X register char *p;
X char *login;
X char *buf;
X{
X register char *bp = buf;
X
X if (*p == '*')
X p++;
X while (*p != '\0' && *p != ',' && *p != ';' && *p != ':' && *p != '(')
X {
X if (*p == '-') {
X bp = buf;
X p++;
X }
X else if (*p == '&')
X {
X strcpy(bp, login);
X if (islower(*bp))
X *bp = toupper(*bp);
X while (*bp != '\0')
X bp++;
X p++;
X }
X else
X *bp++ = *p++;
X }
X *bp = '\0';
X}
X#endif
*-*-END-of-src/fullname.c-*-*
echo x - src/funcs.c
sed 's/^X//' >src/funcs.c <<'*-*-END-of-src/funcs.c-*-*'
X/*
X * funcs - functions used by many programs
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)funcs.c 2.19 8/28/84";
X#endif !lint
X
X#include "params.h"
X#include <errno.h>
X#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C)
X#include <fcntl.h>
X#endif !v7
X
X/*
X * Append NGDELIM to string.
X */
Xngcat(s)
Xregister char *s;
X{
X if (*s) {
X while (*s++)
X ;
X s -= 2;
X if (*s++ == NGDELIM)
X return;
X }
X *s++ = NGDELIM;
X *s = '\0';
X}
X
X/*
X * News group matching.
X *
X * nglist is a list of newsgroups.
X * sublist is a list of subscriptions.
X * sublist may have "meta newsgroups" in it.
X * All fields are NGDELIM separated,
X * and there is an NGDELIM at the end of each argument.
X *
X * Currently implemented glitches:
X * sublist uses 'all' like shell uses '*', and '.' like shell '/'.
X * If subscription X matches Y, it also matches Y.anything.
X */
Xngmatch(nglist, sublist)
Xregister char *nglist, *sublist;
X{
X register char *n, *s;
X register int rc;
X
X rc = FALSE;
X for (n = nglist; *n != '\0' && rc == FALSE;) {
X for (s = sublist; *s != '\0';) {
X if (*s != NEGCHAR)
X rc |= ptrncmp(s, n);
X else
X rc &= ~ptrncmp(s+1, n);
X while (*s++ != NGDELIM && *s != '\0')
X ;
X }
X while (*n++ != NGDELIM && *n != '\0')
X ;
X }
X return(rc);
X}
X
X/*
X * Compare two newsgroups for equality.
X * The first one may be a "meta" newsgroup.
X */
Xptrncmp(ng1, ng2)
Xregister char *ng1, *ng2;
X{
X while (*ng1 != NGDELIM && *ng1 != '\0') {
X if (ng1[0]=='a' && ng1[1]=='l' && ng1[2]=='l') {
X ng1 += 3;
X while (*ng2 != NGDELIM && *ng2 != '.' && *ng2 != '\0')
X if (ptrncmp(ng1, ng2++))
X return(TRUE);
X return (ptrncmp(ng1, ng2));
X } else if (*ng1++ != *ng2++)
X return(FALSE);
X }
X return (*ng2 == '.' || *ng2 == NGDELIM || *ng2 == '\0');
X}
X
X/*
X * Exec the shell.
X * This version resets uid, gid, and umask.
X * Called with fsubr(ushell, s, NULL)
X */
X/* ARGSUSED */
Xushell(s, dummy)
Xchar *s, *dummy;
X{
X umask(savmask);
X setgid(gid);
X setuid(uid);
X xshell(s);
X}
X
X/*
X * Exec the shell.
X * This version restricts PATH to bin and /usr/bin.
X * Called with fsubr(pshell, s, NULL)
X */
Xextern char **environ;
X
X/* ARGSUSED */
Xpshell(s, dummy)
Xchar *s, *dummy;
X{
X static char *penv[] = { SYSPATH, NULL };
X register char **ep, *p;
X register int found;
X
X found = FALSE;
X for (ep = environ; p = *ep; ep++) {
X if (strncmp(p, "PATH=", 5) == 0) {
X *ep = penv[0];
X found = TRUE;
X }
X }
X if (!found)
X environ = &penv[0];
X xshell(s);
X}
X
X/*
X * Exec the shell.
X */
Xxshell(s)
Xchar *s;
X{
X execl(SHELL, SHELL, "-c", s, (char *)0);
X xerror("No shell!");
X}
X
X/*
X * Fork and call a subroutine with two args.
X * Return pid without waiting.
X */
Xfsubr(f, s1, s2)
Xint (*f)();
Xchar *s1, *s2;
X{
X register int pid;
X
X while ((pid = fork()) == -1)
X sleep((unsigned)1);
X if (pid == 0) {
X (*f)(s1, s2);
X exit(0);
X }
X return(pid);
X}
X
X/*
X * Wait on a child process.
X */
Xfwait(pid)
Xregister int pid;
X{
X register int w;
X int status;
X int (*onhup)(), (*onint)();
X
X onint = signal(SIGINT, SIG_IGN);
X onhup = signal(SIGHUP, SIG_IGN);
X while ((w = wait(&status)) != pid && w != -1)
X ;
X if (w == -1)
X status = -1;
X signal(SIGINT, onint);
X signal(SIGHUP, onhup);
X return(status);
X}
X
X/*
X * Strip trailing newlines, blanks, and tabs from 's'.
X * Return TRUE if newline was found, else FALSE.
X */
Xnstrip(s)
Xregister char *s;
X{
X register char *p;
X register int rc;
X
X rc = FALSE;
X p = s;
X while (*p)
X if (*p++ == '\n')
X rc = TRUE;
X while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t'));
X *++p = '\0';
X return(rc);
X}
X
X/*
X * Delete trailing NGDELIM.
X */
Xngdel(s)
Xregister char *s;
X{
X if (*s++) {
X while (*s++);
X s -= 2;
X if (*s == NGDELIM)
X *s = '\0';
X }
X}
X
X/*
X * Return the ptr in sp at which the character c appears;
X * NULL if not found
X *
X * These are the v7 index and rindex routines, stolen for portability.
X * (Some Unix systems call them strchr and strrchr, notably PWB 2.0
X * and its derivitives such as Unix/TS 2.0, Unix 3.0, etc.) Others,
X * like v6, don't have them at all.
X */
X
Xchar *
Xindex(sp, c)
Xregister char *sp, c;
X{
X do {
X if (*sp == c)
X return(sp);
X } while (*sp++);
X return(NULL);
X}
X
X/*
X * Return the ptr in sp at which the character c last
X * appears; NULL if not found
X */
X
Xchar *
Xrindex(sp, c)
Xregister char *sp, c;
X{
X register char *r;
X
X r = NULL;
X do {
X if (*sp == c)
X r = sp;
X } while (*sp++);
X return(r);
X}
X
X/*
X * Local open routine.
X */
XFILE *
Xxfopen(name, fmode)
Xregister char *name, *fmode;
X{
X register FILE *fp;
X char *fname;
X extern int errno, sys_nerr;
X extern char *sys_errlist[];
X
X if ((fp = fopen(name, fmode)) == NULL) {
X#ifdef IHCC
X /*
X * IHCC users only see the "filename" that was in trouble,
X * not the whole path. (for security!)
X */
X fname = rindex(name, '/') + 1;
X#else
X fname = name;
X#endif
X if (errno > sys_nerr)
X sprintf(bfr, "Cannot open %s (%s): Error %d",
X fname, fmode, errno);
X else
X sprintf(bfr, "Cannot open %s (%s): %s",
X fname, fmode, sys_errlist[errno]);
X xerror(bfr);
X }
X /* kludge for setuid not being honored for root */
X if ((uid == 0) && (duid != 0) && ((fmode == "a") || (fmode == "w")))
X chown(name, duid, dgid);
X return(fp);
X}
X
Xprefix(full, pref)
Xregister char *full, *pref;
X{
X register char fc, pc;
X
X do {
X fc = *full++;
X pc = *pref++;
X if (isupper(fc))
X fc = tolower(fc);
X if (isupper(pc))
X pc = tolower(pc);
X } while (fc == pc);
X if (*--pref == 0)
X return 1;
X else
X return 0;
X}
X
Xchar *
Xdirname(ngname)
Xchar *ngname;
X{
X static char rbuf[BUFLEN];
X register char *p;
X
X sprintf(rbuf, "%s/%s", SPOOL, ngname);
X
X /* Use the new style name for all new stuff. */
X for (p=rbuf+strlen(SPOOL); *p; p++)
X if (*p == '.')
X *p = '/';
X return rbuf;
X}
X
X/*
X * Return TRUE iff ngname is a valid newsgroup name
X */
Xvalidng(ngname)
Xchar *ngname;
X{
X register FILE *fp;
X register char *p, *q;
X char abuf[BUFLEN];
X
X fp = xfopen(ACTIVE, "r");
X while(fgets(abuf, BUFLEN, fp) != NULL) {
X p = abuf;
X q = ngname;
X while (*p++ == *q++)
X ;
X if (*--q == '\0' && *--p == ' ') {
X fclose(fp);
X return TRUE;
X }
X }
X fclose(fp);
X return FALSE;
X}
X
X/* VARARGS1 */
Xxerror(message, arg1, arg2, arg3)
Xchar *message;
Xint arg1, arg2, arg3;
X{
X char buffer[128];
X extern char *Progname;
X
X fflush(stdout);
X sprintf(buffer, message, arg1, arg2, arg3);
X logerr(buffer);
X xxit(1);
X}
X
X/* VARARGS1 */
Xlog(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
Xchar *fmt;
X{
X _dolog(0, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
X}
X
X/* VARARGS1 */
Xlogerr(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
Xchar *fmt;
X{
X _dolog(1, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
X}
X
Xchar *lfsuffix[] = {
X "log",
X "errlog",
X 0
X};
X
X
X/*
X * Log the given message, with printf strings and parameters allowed,
X * on the log file, if it can be written. The date and an attempt at
X * figuring out the remote system name are also logged.
X */
X/* VARARGS1 */
X_dolog(which, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
Xchar *fmt;
X{
X FILE *logfile;
X register char *p, *q, *logtime;
X int i;
X char logfname[BUFLEN]; /* the log file */
X char rmtsys[BUFLEN];
X char msg[BUFLEN];
X char c;
X time_t t;
X
X if (header.relayversion[0]) {
X for (p=header.relayversion; p; p=index(p+1, 's'))
X if (strncmp(p, "site ", 5) == 0)
X break;
X if (p == NULL)
X goto crackpath;
X p += 4;
X while (*p == ' ' || *p == '\t')
X p++;
X for (q=p; *q && *q!=' ' && *q != '\t'; q++)
X ;
X c = *q;
X strcpy(rmtsys, p);
X *q = c;
X } else {
Xcrackpath:
X strcpy(rmtsys, header.path);
X p = index(rmtsys, '!');
X if (p == NULL)
X p = index(rmtsys, ':');
X if (p)
X *p = 0;
X else {
X p = rindex(rmtsys, '@');
X if (p)
X strcpy(rmtsys, p+1);
X else
X strcpy(rmtsys, "local");
X }
X }
X
X (void) time(&t);
X logtime = ctime(&t);
X logtime[16] = 0;
X logtime += 4;
X
X
X sprintf(msg, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
X
X if (which)
X fprintf(stderr,"%s: %s\n", Progname, msg);
X
X for (i=0; i<=which;i++) {
X sprintf(logfname, "%s/%s", LIB, lfsuffix[i]);
X
X if (access(logfname, 0) == 0 && (logfile = fopen(logfname, "a")) != NULL) {
X#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C)
X int flags;
X flags = fcntl(fileno(logfile), F_GETFL, 0);
X fcntl(fileno(logfile), F_SETFL, flags|O_APPEND);
X#else v7
X lseek(fileno(logfile), 0L, 2);
X#endif v7
X if (i)
X fprintf(logfile, "%s\t%s\t%s: %s\n", logtime,
X header.ident, Progname, msg);
X else
X fprintf(logfile, "%s\t%s\t%s\n", logtime,
X rmtsys, msg);
X fclose(logfile);
X }
X }
X}
*-*-END-of-src/funcs.c-*-*
echo x - src/funcs2.c
sed 's/^X//' >src/funcs2.c <<'*-*-END-of-src/funcs2.c-*-*'
X/*
X * funcs2 - functions used by both inews and readnews.
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)funcs2.c 1.5 8/28/84";
X#endif !lint
X
X#include "params.h"
X
X/*
X * Get user name and home directory.
X */
Xgetuser()
X{
X static int flag = TRUE;
X register struct passwd *p;
X
X if (flag) {
X if ((p = getpwuid(uid)) == NULL)
X xerror("Cannot get user's name");
X if ( username == NULL || username[0] == 0)
X username = AllocCpy(p->pw_name);
X userhome = AllocCpy(p->pw_dir);
X flag = FALSE;
X }
X strcpy(header.path, username);
X}
X
Xstatic FILE *sysfile;
X
Xchar *fldget();
X
X/*
X * Open SUBFILE.
X */
Xs_openr()
X{
X sysfile = xfopen(SUBFILE, "r");
X}
X
X/*
X * Read SUBFILE.
X */
Xs_read(sp)
Xregister struct srec *sp;
X{
X register char *p;
Xagain:
X p = bfr;
X if (fgets(p, LBUFLEN, sysfile) == NULL)
X return(FALSE);
X if (!nstrip(p))
X xerror("SUBFILE line too long.");
X if (*p == '#')
X goto again;
X sp->s_xmit[0] = '\0';
X sp->s_flags[0] = '\0';
X
X p = fldget(sp->s_name, p);
X if (*p++ == '\0')
X xerror("Bad SUBFILE line.");
X/*
X * A sys file line reading "ME" means the name of the local system.
X */
X if (strcmp(sp->s_name, "ME") == 0)
X strcpy(sp->s_name, FULLSYSNAME);
X p = fldget(sp->s_nbuf, p);
X lcase(sp->s_nbuf);
X ngcat(sp->s_nbuf);
X if (*p++ == '\0')
X return(TRUE);
X
X p = fldget(sp->s_flags, p);
X if (*p++ == '\0')
X return(TRUE);
X
X (void) fldget(sp->s_xmit, p);
X return(TRUE);
X}
X
Xchar *
Xfldget(q, p)
Xregister char *q, *p;
X{
X while (*p && *p != ':') {
X if (*p == '\\' && p[1]==':')
X p++;
X *q++ = *p++;
X }
X *q = '\0';
X return(p);
X}
X
X/*
X * Find the SUBFILE record for a system.
X */
Xs_find(sp, system)
Xregister struct srec *sp;
Xchar *system;
X{
X s_openr();
X while (s_read(sp))
X if (strncmp(system, sp->s_name, SNLN) == 0) {
X s_close();
X return(TRUE);
X }
X s_close();
X return(FALSE);
X}
X
X/*
X * Close sysfile.
X */
Xs_close()
X{
X fclose(sysfile);
X}
X
Xtime_t
Xcgtdate(datestr)
Xchar *datestr;
X{
X time_t i;
X char junk[40],month[40],day[30],tod[60],year[50];
X
X if ((i = getdate(datestr, (struct timeb *) NULL)) >= 0)
X return i;
X sscanf(datestr, "%s %s %s %s %s", junk, month, day, tod, year);
X sprintf(bfr, "%s %s, %s %s", month, day, year, tod);
X return getdate(bfr, (struct timeb *) NULL);
X}
X
Xlcase(s)
Xregister char *s;
X{
X register char *ptr;
X
X for (ptr = s; *ptr; ptr++)
X if (isupper(*ptr))
X *ptr = tolower(*ptr);
X}
X
Xohwrite(hp, fp)
Xregister struct hbuf *hp;
Xregister FILE *fp;
X{
X ngdel(strcpy(bfr, hp->nbuf));
X fprintf(fp, "A%s\n%s\n%s!%s\n%s\n%s\n", hp->oident, bfr, FULLSYSNAME, hp->path, hp->subdate, hp->title);
X}
X
X/*
X * Return a compact representation of the person who posted the given
X * message. A sender or internet name will be used, otherwise
X * the last part of the path is used preceeded by an optional ".."
X */
Xchar *
Xtailpath(hp)
Xstruct hbuf *hp;
X{
X char *p, *r;
X static char resultbuf[BUFLEN];
X char pathbuf[PATHLEN];
X char *malloc();
X
X /*
X * This only happens for articles posted by old news software
X * in non-internet format.
X */
X resultbuf[0] = '\0';
X strcpy(pathbuf, hp->path);
X p = index(pathbuf, ' ');
X if (p)
X *p = '\0'; /* Chop off trailing " (name)" */
X r = rindex(pathbuf, '!');
X if (r == 0) {
X r = pathbuf;
X }
X else {
X while (r > pathbuf && *--r != '!')
X ;
X if (r > pathbuf) {
X r++;
X strcpy(resultbuf, "..!");
X }
X }
X strcat(resultbuf, r);
X return resultbuf;
X}
X
X/*
X * arpadate is like ctime(3) except that the time is returned in
X * an acceptable ARPANET time format instead of ctime format.
X */
Xchar *
Xarpadate(longtime)
Xtime_t *longtime;
X{
X register char *p, *q, *ud;
X register int i;
X static char b[40];
X extern struct tm *gmtime();
X extern char *asctime();
X
X /* Get current time. This will be used resolve the timezone. */
X ud = asctime(gmtime(longtime));
X
X /* Crack the UNIX date line in a singularly unoriginal way. */
X q = b;
X
X#ifdef notdef
X/* until every site installs the fix to getdate.y, the day
X of the week can cause time warps */
X p = &ud[0]; /* Mon */
X *q++ = *p++;
X *q++ = *p++;
X *q++ = *p++;
X *q++ = ','; *q++ = ' ';
X#endif
X
X p = &ud[8]; /* 16 */
X if (*p == ' ')
X p++;
X else
X *q++ = *p++;
X *q++ = *p++; *q++ = ' ';
X
X p = &ud[4]; /* Sep */
X *q++ = *p++; *q++ = *p++; *q++ = *p++; *q++ = ' ';
X
X p = &ud[22]; /* 1979 */
X *q++ = *p++; *q++ = *p++; *q++ = ' ';
X
X p = &ud[11]; /* 01:03:52 */
X for (i = 8; i > 0; i--)
X *q++ = *p++;
X
X *q++ = ' ';
X *q++ = 'G'; /* GMT */
X *q++ = 'M';
X *q++ = 'T';
X *q = '\0';
X
X return (b);
X}
X
Xchar *
Xreplyname(hptr)
Xstruct hbuf *hptr;
X{
X register char *ptr;
X register char *ptr2;
X static char tbuf[PATHLEN];
X
X ptr = hptr->path;
X if (prefix(ptr, FULLSYSNAME))
X ptr = index(ptr, '!') + 1;
X#ifdef INTERNET
X if (hptr->from[0])
X ptr = hptr->from;
X if (hptr->replyto[0])
X ptr = hptr->replyto;
X#endif
X strcpy(tbuf, ptr);
X ptr = index(tbuf, '(');
X if (ptr) {
X while (ptr[-1] == ' ')
X ptr--;
X *ptr = 0;
X }
X#ifndef INTERNET
X /*
X * Play games stripping off multiple berknet
X * addresses (a!b!c:d:e => a!b!d:e) here.
X */
X for (ptr=tbuf; *ptr; ptr++)
X if (index(NETCHRS, *ptr) && *ptr == ':' && (ptr2=index(ptr+1, ':')))
X strcpy(ptr, ptr2);
X#endif !INTERNET
X return tbuf;
X}
X
X#ifdef DBM
Xtypedef struct {
X char *dptr;
X int dsize;
X} datum;
X#endif DBM
X
X/*
X * Given an article ID, find the line in the history file that mentions it.
X * Return the text of the line, or NULL if not found. A pointer to a
X * static area is returned.
X */
Xchar *
Xfindhist(artid)
Xchar *artid;
X{
X static char lbuf[256];
X char oidbuf[BUFSIZ];
X FILE *hfp;
X register char *p;
X#ifdef DBM
X datum lhs, rhs;
X datum fetch();
X#endif DBM
X
X /* Try to understand old artid's as well. Assume .UUCP domain. */
X if (artid[0] != '<') {
X p = index(artid, '.');
X if (p)
X *p++ = '\0';
X sprintf(oidbuf, "<%s@%s.UUCP>", p, artid);
X if (p)
X *--p = '.';
X } else
X strcpy(oidbuf, artid);
X p = oidbuf;
X while (*++p)
X if (isupper(*p))
X *p = tolower(*p);
X
X hfp = xfopen(ARTFILE, "r");
X#ifdef DBM
X dbminit(ARTFILE);
X lhs.dptr = oidbuf;
X lhs.dsize = strlen(lhs.dptr) + 1;
X rhs = fetch(lhs);
X if (rhs.dptr) {
X fseek(hfp, (long)rhs.dptr, 0);
X#endif DBM
X while (fgets(lbuf, BUFLEN, hfp) != NULL) {
X p = index(lbuf, '\t');
X if (p == NULL)
X p = index(lbuf, '\n');
X *p = 0;
X if (strcmp(lbuf, artid) == 0 || strcmp(lbuf, oidbuf) == 0) {
X fclose(hfp);
X *p = '\t';
X *(lbuf + strlen(lbuf) - 1) = 0; /* zap the \n */
X return(lbuf);
X }
X }
X#ifdef DBM
X }
X#endif DBM
X fclose(hfp);
X return(NULL);
X}
X
X/*
X * Hunt up the article "artid", and return the newsgroup/artnum
X * where it can be found.
X */
Xchar *
Xfindfname(artid)
Xchar *artid;
X{
X char *line, *p, *q;
X char *findhist();
X static char fname[256];
X
X line = findhist(artid);
X if (line) {
X /* Look for it stored as an article, where it should be */
X p = index(line, '\t');
X p = index(p+1, '\t');
X p++;
X if (*p) {
X q = index(p, ' ');
X if (q)
X *q = 0;
X strcpy(fname, p);
X return fname;
X }
X }
X
X return NULL;
X}
X
X/*
X * Hunt up the article "artid", fopen it for read, and return a
X * file descriptor to it. We look everywhere we can think of.
X */
XFILE *
Xhfopen(artid)
Xchar *artid;
X{
X char *p;
X char *findhist();
X FILE *rv = NULL;
X char fname[256];
X
X p = findfname(artid);
X if (p) {
X strcpy(fname, dirname(p));
X rv = fopen(fname, "r"); /* NOT xfopen! */
X if (rv != NULL)
X return rv;
X }
X
X xerror("Cannot hfopen article %s", artid);
X#ifdef lint
X return NULL;
X#endif lint
X}
*-*-END-of-src/funcs2.c-*-*
exit
More information about the Comp.sources.unix
mailing list