rick@seismo.UUCP (Rick Adams) (09/11/84)
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