Vnews part 2 (of 7)
sources-request at genrad.UUCP
sources-request at genrad.UUCP
Fri Jan 25 09:04:24 AEST 1985
# From: ka at hou3c
#
# Welcome to vnews release 2.11-B 1/17/85.
# This is part 2 out of 7.
# Feed me into sh (NOT csh).
if test ! -d artfile
then mkdir artfile
fi
if test ! -d lib
then mkdir lib
fi
cat > artfile/ifuncs.c.10.2 <<\!E!O!F!
/*
* ifuncs - functions used by inews.
*/
#ifndef lint
static char *SccsId = "@(#)ifuncs.c 2.35 9/12/84";
#endif !lint
#include "iparams.h"
#include <errno.h>
/*
* Transmit this article to all interested systems.
*/
#ifdef u370
static struct srec srec;
#endif
static struct hbuf h, hh;
broadcast()
{
register char *nptr, *hptr;
register FILE *fp;
#ifndef u370
struct srec srec;
#endif
char sentbuf[BUFLEN];
int nsent = 0;
/* h is a local copy of the header we can scribble on */
fp = xfopen(ARTICLE, "r");
if (hread(&h, fp, TRUE) == NULL)
xerror("Cannot reread article");
fclose(fp);
strcpy(sentbuf, h.ident);
strcat(sentbuf, " sent to ");
nsent = 0;
/* break path into list of systems. */
hptr = nptr = h.path;
while (*hptr != '\0') {
if (index(NETCHRS, *hptr)) {
*hptr++ = '\0';
nptr = hptr;
} else
hptr++;
}
*nptr = '\0';
/* loop once per system. */
lock();
s_openr();
while (s_read(&srec)) {
if (strncmp(srec.s_name, FULLSYSNAME, SNLN) == 0)
continue;
hptr = h.path;
while (*hptr != '\0') {
if (strncmp(srec.s_name, hptr, SNLN) == 0)
goto contin;
while (*hptr++ != '\0')
;
}
if (ngmatch(h.nbuf, srec.s_nbuf)) {
if (h.distribution[0] == '\0' ||
ngmatch(h.distribution, srec.s_nbuf) ||
ngmatch(h.nbuf, h.distribution)) {
if (transmit(&srec, xfopen(ARTICLE, "r"), 1)) {
if (nsent)
strcat(sentbuf, ", ");
strcat(sentbuf, srec.s_name);
nsent++;
}
}
}
contin:;
}
if (nsent)
log(sentbuf);
s_close();
unlock();
}
/*
* Transmit file to system.
*/
#define PROC 0004
transmit(sp, ifp, maynotify)
register struct srec *sp;
register FILE *ifp;
int maynotify;
{
register FILE *ofp;
register int c;
register char *ptr;
char TRANS[BUFLEN];
char *argv[20];
register int pid;
extern char firstbufname[];
/* A: afmt: the other machine runs an A news, so we xmit in A format */
int afmt = (index(sp->s_flags, 'A') != NULL);
/* B: use B format (this is the default - don't use this letter elsewise). */
/* F: append name to file */
int appfile = (index(sp->s_flags, 'F') != NULL);
/* H: history: expand %s into the history line (KSA) */
int history = (index(sp->s_flags, 'H') != NULL); /* (6/18/84 KSA) */
/* L: local: don't send the article unless it was generated locally */
int local = (index(sp->s_flags, 'L') != NULL);
/* N: notify: don't send the article, just tell him we have it */
int notify = maynotify && (index(sp->s_flags, 'N') != NULL);
/* S: noshell: don't fork a shell to execute the xmit command */
int noshell = (index(sp->s_flags, 'S') != NULL);
/* U: useexist: use the -c option to uux to use the existing copy */
int useexist = (index(sp->s_flags, 'U') != NULL);
if (local && mode == PROC) {
fclose(ifp);
return FALSE;
}
#ifdef DEBUG
printf("Transmitting to '%s'\n", sp->s_name);
#endif
if (!appfile && !useexist && !history) { /* (6/18/84 KSA) */
if (hread(&hh, ifp, TRUE) == NULL) {
logerr("Bad header, not transmitting %s re %s to %s",
hh.ident, hh.title, sp->s_name);
fclose(ifp);
return FALSE;
}
if (hh.nbuf[0] == '\0') {
fprintf(stderr, "Article not subscribed to by %s\n", sp->s_name);
fclose(ifp);
return FALSE;
}
sprintf(TRANS, "%s/trXXXXXX", SPOOL);
}
if (notify) {
char oldid[50];
sprintf(hh.title, "ihave %s %s", hh.ident, FULLSYSNAME);
sprintf(hh.nbuf, "to.%s.ctl", sp->s_name);
strcpy(oldid, hh.ident);
getident(&hh);
log("tell %s about %s, notif. id %s",
sp->s_name, oldid, hh.ident);
}
if (appfile) {
if (firstbufname[0] == '\0') {
extern char histline[];
localize("junk");
savehist(histline);
xerror("No file name to xmit from");
}
#ifdef IHCC
sprintf(TRANS, "%s/%s/%s", logdir(HOME), BATCHDIR, sp->s_xmit);
ofp = fopen(TRANS, "a");
#else
ofp = fopen(sp->s_xmit, "a");
#endif
if (ofp == NULL)
xerror("Cannot append to %s", sp->s_xmit);
fprintf(ofp, "%s\n", firstbufname);
fclose(ofp);
fclose(ifp);
return TRUE;
}
else
#ifdef UXMIT
if (useexist) {
if (firstbufname[0] == '\0')
xerror("No file name to xmit from");
if (*sp->s_xmit == '\0')
sprintf(bfr, UXMIT, sp->s_name, firstbufname);
else
sprintf(bfr, sp->s_xmit, firstbufname);
fclose(ifp);
} else
#endif
if (history) { /* (6/18/84 KSA) */
extern char histline[];
if (*sp->s_xmit == '\0')
xerror("no xmit command with H flag");
sprintf(bfr, sp->s_xmit, histline);
} else
{
ofp = xfopen(mktemp(TRANS), "w");
if (afmt)
ohwrite(&hh, ofp);
else
hwrite(&hh, ofp);
if (!notify)
while ((c = getc(ifp)) != EOF)
putc(c, ofp);
fclose(ifp);
fclose(ofp);
if (*sp->s_xmit == '\0')
sprintf(bfr, DFTXMIT, sp->s_name, TRANS);
else
sprintf(bfr, "(%s) < %s", sp->s_xmit, TRANS);
}
/* At this point, the command to be executed is in bfr. */
if (noshell) {
if (pid = fork())
fwait(pid);
else {
close(0);
open(TRANS, 0);
if (*sp->s_xmit == '\0')
ptr = bfr;
else
ptr = sp->s_xmit;
for (pid = 0; pid < 19; pid++) {
while (isspace(*ptr))
*ptr++ = 0;
argv[pid] = ptr;
while (!isspace(*++ptr) && *ptr)
;
if (!*ptr)
break;
}
argv[++pid] = 0;
execv(argv[0], argv);
xerror("Can't execv %s", argv[0]);
}
} else
system(bfr);
if (!appfile && !useexist && !history) /* 6/18/84 KSA) */
unlink(TRANS);
fclose(ifp);
return TRUE;
}
typedef struct {
char *dptr;
int dsize;
} datum;
/*
* Return TRUE if we have seen this file before, else FALSE.
*/
history(hp)
struct hbuf *hp;
{
#ifdef DBM
datum lhs, rhs;
datum fetch();
#else !DBM
register FILE *hfp;
#endif !DBM
register char *p;
char lcident[BUFLEN];
#ifdef DEBUG
fprintf(stderr,"history(%s)\n", hp->ident);
#endif
/*
* Make the article ID case insensitive.
*/
strcpy(lcident, hp->ident);
p = lcident;
while (*++p)
if (isupper(*p))
*p = tolower(*p);
idlock(lcident);
#ifdef DBM
dbminit(ARTFILE);
lhs.dptr = lcident;
lhs.dsize = strlen(lhs.dptr) + 1;
rhs = fetch(lhs);
if (rhs.dptr)
return(TRUE);
#else
hfp = xfopen(ARTFILE, "r");
while (fgets(bfr, BUFLEN, hfp) != NULL) {
p = index(bfr, '\t');
if (p == NULL)
p = index(bfr, '\n');
if (p != NULL) /* can happen if nulls in file */
*p = 0;
p = bfr;
while (*++p)
if (isupper(*p))
*p = tolower(*p);
if (strcmp(bfr, lcident)==0 ||
hp->oident[0] && strcmp(bfr, hp->oident)==0) {
fclose(hfp);
idunlock();
#ifdef DEBUG
fprintf(stderr,"history returns true\n");
#endif
return(TRUE);
}
}
fclose(hfp);
#endif
addhist(hp->ident);
addhist("\t");
#ifdef DEBUG
fprintf(stderr,"history returns false\n");
#endif
return(FALSE);
}
char histline[256]; /* Assumed initially zero */
addhist(msg)
char *msg;
{
strcat(histline, msg);
}
savehist(hline)
char *hline;
{
register FILE *hfp;
datum lhs, rhs;
long fpos;
register char *p;
hfp = xfopen(ARTFILE, "a");
fpos = ftell(hfp);
fprintf(hfp, "%s\n", hline);
fclose(hfp);
#ifdef DBM
/* We assume that history has already been called, calling dbminit. */
p = index(hline, '\t');
if (p)
*p = 0;
p = hline;
while(*++p)
if(isupper(*p))
*p = tolower(*p);
lhs.dptr = hline;
lhs.dsize = strlen(lhs.dptr) + 1;
rhs.dptr = (char *) &fpos;
rhs.dsize = sizeof fpos;
store(lhs, rhs);
#endif
hline[0] = 0;
idunlock();
}
/*
* Save partial news.
*/
newssave(fd, dummy)
FILE *fd;
char *dummy;
{
register FILE *tofd, *fromfd;
char sfname[BUFLEN];
register int c;
time_t tim;
#ifdef lint
c = *dummy;
#endif lint
if (fd == NULL)
fromfd = xfopen(INFILE, "r");
else
fromfd = fd;
umask(savmask);
setgid(gid);
setuid(uid);
sprintf(sfname, "%s/%s", userhome, PARTIAL);
if ((tofd = fopen(sfname, "a")) == NULL)
xerror("Cannot save partial news in %s", sfname);
time(&tim);
fprintf(tofd, "----- News saved at %s\n", arpadate(&tim));
while ((c = getc(fromfd)) != EOF)
putc(c, tofd);
fclose(fromfd);
fclose(tofd);
printf("News saved in %s\n", sfname);
xxit(0);
}
/*
* Handle dates in header.
*/
dates(hp)
struct hbuf *hp;
{
time_t edt;
time(&hp->rectime);
strcpy(hp->recdate, arpadate(&hp->rectime));
nstrip(hp->recdate);
if (*hp->subdate) {
if (cgtdate(hp->subdate) < 0) {
xerror("Cannot parse submittal date '%s'", hp->subdate);
}
} else
strcpy(hp->subdate, hp->recdate);
if (*hp->expdate) {
if ((edt = cgtdate(hp->expdate)) < 0)
xerror("Cannot parse expiration date '%s'",hp->expdate);
nstrip(strcpy(hp->expdate, arpadate(&edt)));
} else {
defexp = TRUE;
/*
* Default is now applied in expire.c
hp->exptime = hp->rectime + DFLTEXP;
nstrip(strcpy(hp->expdate, arpadate(&hp->exptime)));
*/
}
}
char lockname[80];
idlock(str)
char *str;
{
register int i;
char tempname[80];
time_t now;
struct stat sbuf;
#ifdef VMS
int fd;
sprintf(lockname, "/tmp/%s.l.1", str);
if ((fd = creat(lockname, 0444)) < 0) {
#else !VMS
sprintf(tempname, "/tmp/LTMP.%d", getpid());
sprintf(lockname, "/tmp/L%s", str);
#ifdef FOURTEENMAX
lockname[5 /* /tmp/ */ + 14] = '\0';
#endif
close(creat(tempname, 0666));
while (link(tempname, lockname)) {
#endif !VMS
(void) time(&now);
i = stat(lockname, &sbuf);
if (i < 0) {
xerror("Directory permission problem in /tmp");
}
if (sbuf.st_mtime + 10*60 < now) {
unlink(lockname);
logerr("Article %s locked up", str);
continue;
}
log("waiting on lock for %s", lockname);
sleep((unsigned)60);
}
#ifdef VMS
close(fd);
#else
unlink(tempname);
#endif
unlink(tempname);
}
idunlock()
{
unlink(lockname);
}
/*
* Put a unique name into header.ident.
*/
getident(hp)
struct hbuf *hp;
{
long seqn;
register FILE *fp;
lock();
fp = xfopen(SEQFILE, "r");
fgets(bfr, BUFLEN, fp);
fclose(fp);
seqn = atol(bfr) + 1;
#ifdef VMS
unlink(SEQFILE);
#endif VMS
fp = xfopen(SEQFILE, "w");
fprintf(fp, "%ld\n", seqn);
fclose(fp);
unlock();
sprintf(hp->ident, "<%ld@%s%s>", seqn, FULLSYSNAME, MYDOMAIN);
}
/*
* Check that header.nbuf contains only valid newsgroup names;
* exit with error if not valid.
*
*/
ngfcheck(isproc)
int isproc;
{
register char *s1, *s2;
register FILE *f;
register char *os1;
int ngroups = 1;
char tbuf[BUFLEN], ngcheck[AFSIZ];
f = xfopen(ACTIVE, "r");
s1 = ngcheck;
while (fgets(bfr, BUFLEN, f) != NULL) {
os1 = s1;
for(s2 = bfr; *s2 != '\0' && *s2 != ' ';) {
if (s1 >= &ngcheck[AFSIZ-2])
xerror("ACTIVE file too long");
*s1++ = *s2++;
}
*s1++ = '\0';
if (isproc) /* don't check to see if can post to this group */
continue;
while (*s2++ != '\0' && *s2 != ' ')
; /* skip max article number */
while (*s2++ != '\0' && *s2 != ' ')
; /* skip min article number */
if (*s2++ != '\0' && *s2 == 'n')
s1 = os1; /* can't post to this group */
}
*s1++ = '\0';
*s1 = '\0';
fclose(f);
s1 = header.nbuf;
s2 = nbuf;
while (*s1 == NGDELIM || *s1 == ' ')
s1++; /* skip leading junk */
do {
/* there shouldn't be blanks, but give the jerk a break */
if (*s1 == NGDELIM || *s1 == ' ') {
*s2++ = '\0';
ngroups++;
while (*++s1 == NGDELIM || *s1 == ' ')
; /* remove extra commas */
} else
*s2++ = *s1++;
} while (*s1 != '\0');
*s2 = '\0';
s1 = nbuf;
while (*s1 != '\0') { /* for each newsgroup in header */
s2 = ngcheck;
while (*s2 != '\0') { /* for each newsgroup in active file */
if (strcmp(s1, s2) == 0)
break;
while (*s2++ != '\0')
;
}
if (*s2 == '\0') { /* not found. remove it */
if (!isproc) {
logerr("Invalid news group '%s'", s1);
newssave(stdin, (char *)NULL);
}
/* See if it's in our alias list */
f = xfopen(ALIASES,"r");
while (fscanf(f,"%s %s", tbuf, bfr) == 2
&& strcmp(s1, tbuf))
;
fclose(f);
if (strcmp(s1, tbuf) == 0) {
logerr("Aliased newsgroup '%s' to '%s'", s1, bfr);
os1 = s1;
s1 = nbuf;
s2 = tbuf;
while (s1 < os1) /* copy left part */
*s2++ = *s1++;
s1 = bfr;
while (*s1 != '\0') /* copy alias */
*s2++ = *s1++;
*s2++ = '\0';
s1 = os1;
os1 = nbuf + (s2 - tbuf);
while (*s1++ != '\0') /* skip old group */
;
/* copy right part */
tbufcpy(s2, s1);
/* copy back to original buffer */
tbufcpy(nbuf, tbuf);
s1 = os1;
} else {
logerr("Unknown newsgroup '%s' removed", s1);
s2 = s1;
while (*s2++ != '\0') /* skip the bad one */
;
tbufcpy(s1, s2);
}
} else { /* It's in our active file */
os1 = s1;
while (*s1++ != '\0')
;
/* check for local only distribution on incoming
newsgroups. This might occur if someone posted to
general,net.unix */
if(isproc && ngroups > 1 && index(os1, '.') == NULL) {
logerr("Local group '%s' removed", os1);
tbufcpy(os1, s1);
s1 = os1;
}
}
}
/* remove any duplicates */
os1 = s1 = nbuf;
for(;;) {
if (*s1++ == '\0') {
if (*s1 == '\0')
break;
s2 = s1;
while (*s2 != '\0') {
if (strcmp(os1, s2) == 0) {
logerr("Duplicate '%s' removed",os1);
os1 = s2;
while (*s2++ != '\0') /* skip it */
;
tbufcpy(os1, s2);
} else
while (*s2++ != '\0')
;
}
os1 = s1;
s1[-1] = '\0';
}
}
if (nbuf[0] != '\0') {
s1 = header.nbuf;
s2 = nbuf;
do {
while (*s2 != '\0')
*s1++ = *s2++;
*s1++ = NGDELIM;
} while (*++s2 != '\0');
*s1 = '\0';
return FALSE;
}
return TRUE;
}
tbufcpy(s1, s2)
register char *s1, *s2;
{
do {
while (*s2 != '\0')
*s1++ = *s2++;
*s1++ = '\0';
} while (*++s2 != '\0');
*s1 = '\0';
}
/*
* Figure out who posted the article (which is locally entered).
* The results are placed in the header structure hp.
*/
gensender(hp, logname)
struct hbuf *hp;
char *logname;
{
register char *fn, *p;
char buf[BUFLEN];
char *fullname(), *getenv();
int fd;
fn = getenv("NAME");
if (fn == NULL) {
sprintf(buf, "%s/%s", userhome, ".name");
fd = open(buf, 0);
if (fd >= 0) {
read(fd, buf, sizeof buf);
close(fd);
if (buf[0] >= 'A') {
fn = buf;
for (p=fn; *p; p++)
if (*p < ' ')
*p = '\0';
}
}
}
if (fn == NULL)
fn = fullname(logname);
sprintf(hp->path, "%s", logname);
sprintf(hp->from, "%s@%s%s (%s)", logname, FULLSYSNAME, MYDOMAIN, fn);
}
/*
* Trap interrupts.
*/
onsig(n)
int n;
{
static int numsigs = 0;
/*
* Most UNIX systems reset caught signals to SIG_DFL.
* This bad design requires that the trap be set again here.
* Unfortunately, if the signal recurs before the trap is set,
* the program will die, possibly leaving the lock in place.
*/
if (++numsigs > 100) {
logerr("inews ran away looping on signal %d", n);
xxit(1);
}
signal(n, onsig);
sigtrap = n;
}
#ifdef BATCH
/*
* If the stdin begins with "#", we assume we have been fed a batched
* shell script which looks like this:
* #! rnews 1234
* article with 1234 chars
* #! rnews 4321
* article with 4321 chars
*
* In this case we just exec the unbatcher and let it unpack and call us back.
*
* Note that there is a potential security hole here. If the batcher is
* /bin/sh, someone could ship you arbitrary stuff to run as shell commands.
* The main protection you have is that the effective uid will be news, not
* uucp and not the super user. (That, plus the fact that BATCH is set to
* "unbatch" as the system is distributed.) If you want to run a batched link
* and you are security concious, do not use /bin/sh as the unbatcher.
* the thing to do is to change BATCH in your localize.sh file from /bin/sh
* to some restricted shell which can only run rnews.
*/
checkbatch()
{
int c;
c = getc(stdin);
if (c != EOF)
ungetc(c, stdin);
clearerr(stdin);
if (c == '#') {
char unbatcher[BUFLEN];
sprintf(unbatcher, "%s/%s", LIB, BATCH);
reset_stdin();
execl(unbatcher, "news-unpack", (char *)0);
xerror("Unable to exec shell to unpack news.");
}
}
/*
* We've already done a read on stdin, and we want to seek back to the
* beginning. We want the real file descriptor (beyond buffers) to
* reflect the true beginning. Do whatever is necessary.
*/
reset_stdin()
{
register FILE *ofd;
register int c;
char *ofdname;
long lseek();
/* First try to seek back - if so, it's a cheap way back. */
if (lseek(0, 0L, 0) == 0L)
return;
/* Can't seek, so have to copy input to a file and use that. */
ofdname = "/tmp/inewsXXXXX";
mktemp(ofdname);
ofd = fopen(ofdname, "w");
while ((c=getc(stdin)) != EOF)
putc(c, ofd);
fclose(stdin);
fclose(ofd);
/* Now for a few lower level hacks to reopen stdin and make
* absolutely sure that the right fd's are done for the exec.
*/
(void) close(0); /* make sure stdin is really closed. */
(void) open(ofdname, 0); /* should return zero */
(void) unlink(ofdname); /* to avoid cleaning it up later. */
}
#endif BATCH
/*
* Exit and cleanup.
*/
xxit(status)
int status;
{
unlink(INFILE);
unlink(ARTICLE);
while (lockcount > 0)
unlock();
idunlock();
exit(status);
}
rwaccess(fname)
char *fname;
{
int fd;
fd = open(fname, 2);
if (fd < 0)
return 0;
close(fd);
return 1;
}
exists(fname)
char *fname;
{
int fd;
fd = open(fname, 0);
if (fd < 0)
return 0;
close(fd);
return 1;
}
int lockcount = 0; /* no. of times we've called lock */
#ifdef VMS
#define SUBLOCK "/tmp/netnews.lck.1"
/*
* Newsystem locking.
* These routines are different for VMS because we can not
* effectively simulate links, and VMS supports multiple
* version numbers of files
*/
lock()
{
register int i;
register int fd;
if (lockcount++ == 0) {
i = DEADTIME;
while ((fd = creat(SUBLOCK, 0444)) < 0) {
if (--i < 0) {
unlink(SUBLOCK);
fprintf(stderr,"%s: %s\n", Progname, msg);
logerr("News system locked up");
}
if (i < -3)
xerror("Unable to unlock news system");
sleep((unsigned)1);
}
close(fd);
}
}
unlock()
{
if (--lockcount == 0)
unlink(SUBLOCK);
}
#else !VMS
/*
* Newsystem locking.
*/
lock()
{
register int i;
extern int errno;
if (lockcount++ == 0) {
i = DEADTIME;
while (link(SUBFILE, LOCKFILE)) {
if (errno != EEXIST)
break;
if (--i < 0)
xerror("News system locked up");
sleep((unsigned)1);
}
}
}
unlock()
{
if (--lockcount == 0)
unlink(LOCKFILE);
}
#endif VMS
/*
* Generate the name of the person responsible for posting this article,
* in order to check that two articles were posted by the same person.
*/
char *
senderof(hp)
struct hbuf *hp;
{
char *q, *tp;
char *tailpath();
if (hp->sender[0])
tp = hp->sender;
else if (hp->from[0])
tp = hp->from;
else
tp = tailpath(hp);
/* Remove full name */
q = index(tp, ' ');
if (q)
*q = '\0';
q = malloc((unsigned)(strlen(tp) + 1));
strcpy(q, tp);
return q;
}
!E!O!F!
cat > lib/addrc.c <<\!E!O!F!
/*
* Add a newsgroup onto the end of .newsrc.
*/
#include <stdio.h>
#include "defs.h"
#include "newsrc.h"
addrc(ngp)
struct ngentry *ngp;
{
if (lastng != NULL) {
lastng->ng_next = ngp;
lastng = ngp;
} else {
lastng = firstng = ngp;
}
}
!E!O!F!
cat > lib/af.h <<\!E!O!F!
#include "artfile.h"
#include "stroff.h"
/* length of section of artrec that can be written directly to artfile */
#define A_WRTLEN (int)(stroff(a_nkwords, artrec) + 1)
/* offsets */
#define PARENTOFF (stroff(a_parent, artrec) + 1)
#define CHILDRENOFF (stroff(a_children, artrec) + 1)
#define CHILDCHOFF (stroff(a_childchain, artrec) + 1)
#define GROUPOFF (stroff(a_group[0], artrec) + 1)
#define A_PREFIX 0210 /* this byte precedes each article record */
#define AF_MAGIC 0431 /* magic number to indicate artfile */
#define AF_VERSION 1 /* version number */
struct afheader {
short af_magic; /* magic number (0431) */
short af_version; /* version number */
DPTR af_idtab; /* offset of message id hash table */
DPTR af_nglist; /* pointer to newsgroup chain table */
DPTR af_titletab; /* title hash table */
DPTR af_records; /* start of article records */
DPTR af_free; /* add next record here */
short af_idtlen; /* # elements in message id hash table */
short af_maxng; /* # elements in newsgroup chain table */
short af_ttlen; /* # elements in title hash table */
};
extern struct afheader afhd ;
extern int affd ;
#if BUFSIZ == 1024
#define BSIZE 1024
#else
#define BSIZE 512
#endif
DPTR readptr() ;
#define ngchain(ngnum) (afhd.af_nglist + ngnum * (int)sizeof(DPTR))
#define hashid(msgid) (afhd.af_idtab + hash(msgid, afhd.af_idtlen) * (int)sizeof(DPTR))
#define equal(s1, s2) (strcmp(s1, s2) == 0)
!E!O!F!
cat > lib/aflock.c <<\!E!O!F!
/*
* Lock and unlock the article data base.
*/
#include <stdio.h>
#include <errno.h>
#include "af.h"
#include <sys/types.h>
#include <sys/stat.h>
#include "defs.h"
#include "libextern.h"
static int islocked ;
/*
* Lock the data base. The data base is only locked to avoid multiple
* writers, so the data base may be read and written simultaneously.
*/
aflock() {
char lockfile[FPATHLEN] ;
int ntries ;
struct stat st ;
int fd ;
char pid[10] ;
long time() ;
sprintf(lockfile, "%s/artfile.lck", LIB) ;
ntries = 0 ;
while (islocked++, (fd = creat(lockfile, 0444)) < 0) {
islocked-- ;
if (++ntries == 1 || ntries == 31) {
if (stat(lockfile, &st) >= 0 && st.st_mtime < time((long *)0) - 60) {
unlink(lockfile) ;
continue ;
}
} else if (ntries > 60) {
xerror("Can't lock data base") ;
}
sleep(2) ;
}
sprintf(pid, "%d\n", getpid()) ;
write(fd, pid, strlen(pid)) ;
close(fd) ;
#ifdef notdef /* forget about stdio due to BSD bug */
fseek(affp, 0L, 0) ;
fread((char *)&afhd, sizeof(afhd), 1, affp) ;
#else
lseek(affd, 0L, 0) ;
read(affd, (char *)&afhd, sizeof afhd) ;
#endif
}
afunlock() {
char lockfile[FPATHLEN] ;
if (islocked) {
sprintf(lockfile, "%s/artfile.lck", LIB) ;
unlink(lockfile) ;
islocked-- ;
}
}
!E!O!F!
cat > lib/afopen.c <<\!E!O!F!
#include "defs.h"
#include "libextern.h"
afopen() {
char fname[FPATHLEN] ;
sprintf(fname, "%s/artfile", LIB) ;
genafopen(fname, "r") ;
}
!E!O!F!
cat > lib/allgroups.c <<\!E!O!F!
#include <stdio.h>
#include "config.h"
#include "ng.h"
char *index() ;
nginit() {
int c ;
fseek(ngfp, 0L, 0) ;
while ((c = getc(ngfp)) != '\n' && c != EOF) ;
}
ngread(g)
register struct ngrec *g ;
{
char line[100] ;
register char *p ;
if (fgets(line, 100, ngfp) == NULL)
return 0 ;
if ((p = index(line, ' ')) == NULL)
xerror("corrupted newsgroup file") ;
*p++ = '\0' ;
scopyn(line, g->g_name, sizeof(g->g_name)) ;
g->g_num = atoi(p) ;
g->g_flags = 0 ;
if (index(p, 'm'))
g->g_flags |= G_MOD ;
return 1 ;
}
!E!O!F!
cat > lib/artfile.h <<\!E!O!F!
/*
* Defines for the article data base file
*/
/* flags in artrec structure */
#define A_DUMMY 01 /* placeholder; article not yet arrived */
#define A_EXPIRED 02 /* article has been expired */
#define A_CANCELLED 04 /* article has been cancelled */
#define A_NOFILE 07 /* no file for this article */
typedef long DPTR ; /* file address */
typedef int ARTNO ; /* article number */
#define DNULL 0L
#define MAXNG 5 /* max # newsgroups per article */
#define A_MAXKW 6 /* max # keywords on an article */
#define A_SPACE 576 /* space for storing strings */
struct artgroup {
short a_ngnum; /* number of this newsgroup */
long a_artno; /* number of article within newsgroup */
DPTR a_ngchain; /* pointer to previous article in newsgroup */
};
struct artrec {
long a_subtime; /* when article was posted */
long a_rectime; /* when article was received */
long a_exptime; /* when this article expires (0 if not specified) */
DPTR a_parent; /* article this is a followup to */
DPTR a_children; /* linked list of followups */
DPTR a_childchain; /* link for followup chain */
DPTR a_idchain; /* chain for article id hash */
DPTR a_titlechain; /* title hash chain */
short a_flags; /* various flags */
short a_nlines; /* length of article */
char a_ngroups; /* number of newsgroups this article posted to */
char a_nkwords; /* number of keywords on article */
struct artgroup a_group[MAXNG]; /* list of groups article posted to */
char *a_ident; /* message id */
char *a_title; /* article subject line */
char *a_from; /* author of article */
char *a_file; /* file containing article */
char *a_kword[A_MAXKW]; /* keywords */
char a_space[A_SPACE]; /* space to store strings */
};
extern DPTR nglnext ;
DPTR nglfirst() ;
ARTNO ngltest() ;
DPTR lookart() ;
#define BKWD_GROUP(ngnum, artno, dp, a) for (dp = nglfirst(ngnum) ; (artno = ngltest(ngnum, &(a))) >= 0 ; dp = nglnext)
#define ainit(a)
#define afree(a)
!E!O!F!
cat > lib/arthead.h <<\!E!O!F!
/*
* header.h - Article header format
*/
#define NUNREC 50
#define H_SPACE 1024
#define NHDNAME 24
/* article header */
struct arthead {
char *h_relayversion; /* Relay-Version: */
char *h_postversion; /* Posting-Version: */
char *h_path; /* Path: */
char *h_from; /* From: */
char *h_nbuf; /* Newsgroups: */
char *h_title; /* Subject: */
char *h_ident; /* Message-ID: */
char *h_subdate; /* Date: (submission) */
char *h_oident; /* Article-I.D.: */
char *h_postdate; /* Posted: */
char *h_recdate; /* Date-Received: */
char *h_expdate; /* Expires: */
char *h_references; /* References: */
char *h_ctlmsg; /* Control: */
char *h_sender; /* Sender: */
char *h_replyto; /* Reply-To: */
char *h_followto; /* Followup-To: */
char *h_distribution; /* Distribution: */
char *h_organization; /* Organization: */
char *h_numlines; /* Lines: */
char *h_keywords; /* Keywords: */
char *h_approved; /* Approved: */
char *h_summary; /* Summary: */
char *h_priority; /* Priority: */
char *h_unrec[NUNREC]; /* unrecognized lines */
time_t h_subtime; /* subdate in secs */
time_t h_rectime; /* recdate in secs */
time_t h_exptime; /* expdate in secs */
int h_intnumlines; /* Integer version */
int h_intpriority; /* Integer version */
char *h_space[8]; /* string space */
};
#define hset(hdrline) ((hdrline) != NULL)
FILE *gethead();
!E!O!F!
cat > lib/bcopy.c <<\!E!O!F!
#include "config.h"
#if BSDREL < 42
bcopy(from, to, n)
register char *from, *to ;
{
register int i ;
if ((i = n) != 0) {
do *to++ = *from++ ;
while (--i != 0) ;
}
}
#endif
!E!O!F!
cat > lib/bcopy.pdp <<\!E!O!F!
/ BCOPY(FROM, TO, N) CHAR *FROM, *TO ;
/
/ Copy "n" bytes from "from" to "to".
/
.globl _bcopy
.globl csav, cret
.text
_bcopy: jsr r0, csav / save registers
mov r5, r4 / get arguments...
cmp (r4)+, (r4)+ /
mov (r4)+, r0 / from
mov (r4)+, r1 / to
mov (r4), r2 / byte count
beq ret / if zero then return
bit $1, r1 / is "to" odd
beq 1f / yes...
movb (r0)+, (r1)+ / copy one byte to make it even
dec r2 / and adjust byte count
1: mov r2, r3 / save (low bit of) count
asr r2 / convert from bytes to words
beq 3f / if any words to copy...
bit $1, r0 / is "from" even now?
beq 2f / if not ...
1: movb (r0)+, (r1)+ / copy bytes...
movb (r0)+, (r1)+ / ...
sob r2, 1b / ...
br 3f / else ...
2: mov (r0)+, (r1)+ / copy words...
sob r2, 2b / ...
3: ror r3 / is byte count odd?
bcc ret / if so...
movb (r0)+, (r1)+ / copy odd byte.
ret: jmp cret / return
!E!O!F!
cat > lib/bcopy.u3b <<\!E!O!F!
.file "bcopy.s" # silly assembler wants this line
.globl bcopy
.align 4
bcopy: save &0 # set up stack frame
movw 0(%ap), %r0 # get source
movw 4(%ap), %r1 # and destination
movw 8(%ap), %r2 # get count
movblb # this instruction does it all
ret &0 # return
!E!O!F!
cat > lib/bcopy.vax <<\!E!O!F!
# bcopy (from, to, count) char *from, *to; int count;
#
# Copy "count" bytes from "from" to "to"; not guaranteed to
# work if "from" and "to" overlap.
.align 2
.globl _bcopy
_bcopy:
.word 0
movl 4(ap), r1 # r1 = from
movl 8(ap), r3 # r3 = to
L1:
movzwl $65535, r0 # while more than 65535 bytes to move
cmpl 12(ap), r0
jleq L2 # if <= 65535, break
subl2 r0, 12(ap) # count-=65535 (bytes moved this time)
movc3 r0, (r1), (r3) # r1, r3 magically point to next 65K
brb L1
L2:
movc3 12(ap), (r1), (r3) # move up to 65535 bytes
ret
!E!O!F!
cat > lib/bfr.c <<\!E!O!F!
#include "defs.h"
char bfr[LBUFLEN]; /* general purpose buffer */
!E!O!F!
cat > lib/bzero.c <<\!E!O!F!
/*
* Set nc bytes, starting at cp, to zero.
*/
#include "config.h"
#if BSDREL < 42
bzero(cp, nc)
register char *cp;
register int nc;
{
while (--nc >= 0)
*cp++ = 0;
}
#endif
!E!O!F!
cat > lib/bzero.pdp <<\!E!O!F!
/ BZERO(MEM, N) CHAR *MEM;
/
/ Clear "n" bytes of memory starting at "mem".
/
.globl _bzero
.globl csav, cret
.text
_bzero: jsr r0, csav / save registers
mov 4(r5), r0 / get memory pointer...
mov 6(r5), r1 / ...and count
beq ret / return if zero
bit $1, r0 / is address odd?
beq 1f / yes...
clrb (r0)+ / clear one byte to make it even
dec r1 / and adjust byte count
1: mov r1, r3 / save (low bit of) count
clr r2 / get zero into a register and clear carry
ror r1 / convert count to words.
asr r1 / convert count to double words
bcc 1f / if word count was odd
mov r2, (r0)+ / clear an extra word
tst r1 / reset condition codes on r1
1: beq 3f / while r1 ~= 0
2: mov r2, (r0)+ / clear a word...
mov r2, (r0)+ /
sob r1, 2b / and update count
3: asr r3 / if count was odd
bcc ret /
movb r2, (r0)+ / clear an extra byte
ret: jmp cret / return
!E!O!F!
cat > lib/bzero.u3b <<\!E!O!F!
.file "bzero.u3b" # assembler wants this
# This code relies on the fact that bzero(mem, n) is equivalent to
# strncpy("", mem, n).
.globl bzero
.align 4
bzero: save &1 # set up stack frame and save r8
movw 0(%ap), %r0 # get address
movw 4(%ap), %r1 # and count
movw &0, %r2 # various parameters are zero
movaw zero, %r8 # null string
movccep %r8,%r1,%r0,%r2,%r2 # strncpy insruction
ret &1 # return
.data
zero: .byte 0
!E!O!F!
cat > lib/cancel.c <<\!E!O!F!
/*
* Cancel the article whose header is in hp, by posting a control message
* to cancel it. The scope of the control message depends on who would
* really be willing to cancel it. It is sent as far as it will do any good.
* notauthor is true iff the person posting this article is not the
* real author of the article being cancelled.
*/
#include <stdio.h>
#include <sys/types.h>
#include "config.h"
#include "arthead.h"
#include "libextern.h"
cancel(ofp, hp, notauthor)
FILE *ofp;
struct arthead *hp;
int notauthor;
{
FILE *inews;
char distgroup[64];
int pid;
char bfr[512];
char *index();
FILE *popen();
/* fflush(stdout); */
pid = fork();
if (pid > 0)
return 0;
strcpy(distgroup, hp->h_nbuf);
if (notauthor)
sprintf(distgroup, "to.%s", FULLSYSNAME);
else
sprintf(distgroup, "%s", hp->h_nbuf);
sprintf(bfr, "%s -t 'cmsg cancel %s' -n %s < /dev/null",
XINEWS, hp->h_ident, distgroup);
if ((inews = popen(bfr, "w")) == NULL)
fprintf(ofp, "Can't fork %s\n", XINEWS);
else
pclose(inews);
if (pid == 0)
_exit(0);
return 0;
}
!E!O!F!
cat > lib/cgtdate.c <<\!E!O!F!
#include <stdio.h>
#include <sys/types.h>
#include "config.h"
#ifndef BSDREL >= 7
#include <sys/timeb.h>
#else
struct timeb
{
time_t time;
unsigned short millitm;
short timezone;
short dstflag;
};
#endif
time_t getdate();
long getadate();
time_t
cgtdate(datestr)
char *datestr;
{
time_t i;
char junk[40],month[40],day[30],time[60],year[50];
char bfr[181];
if ((i = getadate(datestr)) != -1L)
return i;
if ((i = getdate(datestr, (struct timeb *) NULL)) >= 0)
return i;
sscanf(datestr, "%s %s %s %s %s", junk, month, day, time, year);
sprintf(bfr, "%s %s, %s %s", month, day, year, time);
return getdate(bfr, (struct timeb *) NULL);
}
!E!O!F!
cat > lib/cgtdatecmd.c <<\!E!O!F!
/*
* This program takes a date as its argument and writes the UN*X internal
* value on the standard output. The primary purpose of this program is
* to make it unnecessary to load the cgtdate routine as part of readnews
* and/or vnews.
*/
#include <stdio.h>
main(argc, argv)
char **argv ;
{
char buf[1024] ;
register int i ;
long tim ;
long cgtdate() ;
buf[0] = '\0' ;
for (i = 1 ; i < argc ; i++) {
strcat(buf, " ") ;
strcat(buf, argv[i]) ;
}
tim = cgtdate(buf) ;
if (tim == -1L)
return 1 ;
printf("%ld\n", tim) ;
return 0 ;
}
!E!O!F!
cat > lib/ckfopen.c <<\!E!O!F!
/*
* Open file, calling xerror on failure.
*/
#include <stdio.h>
#include "config.h"
FILE *
ckfopen(name, mode)
register char *name, *mode;
{
register FILE *fp;
extern int errno;
if ((fp = fopen(name, mode)) == NULL) {
#ifdef IHCC
char *fname, *rindex();
/*
* IHCC users only see the "filename" that was in trouble,
* not the whole path. (for security!)
*/
if ((fname = rindex(name, '/') != NULL)
fname++;
else
fname = name;
xerror("Cannot open %s (%s), errno=%d", fname, mode, errno);
#else
xerror("Cannot open %s (%s), errno=%d", name, mode, errno);
#endif
}
#ifdef notdef /* this doesn't make sense for readnews */
/* kludge for setuid not being honored for root */
if ((uid == 0) && (duid != 0) && ((mode == "a") || (mode == "w")))
chown(name, duid, dgid);
#endif
return(fp);
}
!E!O!F!
cat > lib/ckmalloc.c <<\!E!O!F!
char *
ckmalloc(nbytes)
unsigned nbytes ;
{
register char *p ;
char *malloc() ;
if ((p = malloc(nbytes)) == (char *)0)
xerror("out of space") ;
return p ;
}
!E!O!F!
cat > lib/config.hou3c <<\!E!O!F!
# This is the config file I use on hou3c.
newsusr netnews
newsgrp other
myorg AT&T Bell Labs, Holmdel
mydomain .UUCP
path /bin:/usr/bin:/usr/lbin
spool /tools/netnews/spool
admin ka
notify
admsub
!E!O!F!
cat > lib/config.sample <<\!E!O!F!
#This is a sample config file (with more comments than a real config file
#would contain, of course). First, we list all the possible entries.
#
#Lines in the setup file consist of a name followed by a value. The various
#types of values are string, indicated by "str", integer, indicated by "int",
#and boolean, indicated by "bool". The default value, if any, is indicated
#by DFT. In certain cases, there is a default which is assigned when a null
#value is given for the value. If the value is boolean, the default is "yes",
#other defaults for null values are indicated by NDFT.
#
#
#NAME TYPE DESCRTIPTION
#admin str Netnews administrator. (DFT is your login name)
#admsub str Mandatory subscription list. DFT general,all.announce
#bin str Directory where programs (e. g. inews) placed. DFT /usr/bin
#buflen int Length of various bufs. DFT 128 if small, else 256
#compadmin bool Recompute the numeric admin id each time program run. DFT no
#datelen int Max length of date. DFT 48
#dfteditor str Default editor program. DFT /bin/ed
#dftexp int Default expiration time in days. DFT 14
#dftsub str Default subscription list. DFT all
#fpathlen int Max length of file path name. DFT 64
#ghname bool True if system has gethostname call. DFT yes if 4.2bsd.
#home str Lib and spool are relative to this user's home directory.
#internet bool True if mailer understands internet addresses. DFT yes
#lbuflen int Length of large buffer. DFT 1024
#lib str Directory for misc netnews files. DFT /usr/lib/news
#mailer str Mail program. DFT /bin/mail
#manually bool Require that admin remove groups manually. DFT yes
#maxgroups int Maximum number of newsgroups.
#mydomain str Appended to sys name to get domain name. This entry mandatory.
#myname str System name. Computed at run time if omitted.
#myorg str Organization name. This entry mandatory.
#namelen int Max length of internet address or messge ID. DFT 64
#newsgrp str Group of news software. This entry is mandatory.
#newsrc str Name of newsrc file. DFT .newsrc
#newsusr str Owner of news software. This entry is mandatory.
#notify str Inform person about certain control messages. NDFT admin
#page str Pager program. NDFT /usr/ucb/more
#path str Path use by setup to find various programs. DFT $PATH
#pathlen int Max length of return path. DFT 512
#small bool True if 16 bit address space. DFT yes if on pdp11.
#spool str Directory where articles stored. DFT /usr/spool/news
#sys str Operating system version. (Guessed by default)
#termcap str Name of termcap library. (Guessed by default)
#tmail str Mailer that understands -t option. NDFT /usr/lib/sendmail
#umask int Umask value; use 022 for secure system. DFT 000
#uname bool True if system has uname system call. DFT yes if USG system.
#v7mail bool True if use Version 7 mail format. DFT yes
# OK, now to give our config entries.
# First we give the required ones.
# The login and group owning the netnews software.
newsusr netnews
newsgrp other
# The name of my organization.
myorg AT&T Bell Labs, Holmdel
# My domain.
mydomain .UUCP
# The remaining entries are not required by the setup program.
# Use a standard path for the rest of setup
path /bin:/usr/bin:/usr/lbin
# We don't have room in the /usr file system for the spool directory,
# so we place it elsewhere.
spool /tools/netnews/spool
# Since I am running the setup program, this is unnecessary, but it is
# safer to include it in case somebody else recompiles the news software
# for some reason
admin ka
# I want to be told about create and rmgrp control messages. Since I am
# the person running the config program, they will be sent to me by default.
notify
# Mandatory subscripts are fascist, so no mandatory subscriptions on hou3c.
admsub
# End of sample config file.
!E!O!F!
cat > lib/cpu.c <<\!E!O!F!
/* This file is run through cpp to determine the cpu type */
#ifdef pdp11
Xpdp11
#endif
#ifdef vax
Xvax
#endif
#ifdef u3b
Xu3b
#endif
!E!O!F!
cat > lib/defs.h <<\!E!O!F!
/*
* defs.h - defines for news-related programs.
*
* By convention, the version of the software you are running is taken
* to be news_version below.
*/
#define news_version "B 2.11-B 1/17/84"
/* SCCS ID @(#)defs.dist 2.23 5/3/83 */
#include "newsdefs.h" /* this gets most of the definitions */
#define FOLLOWUP INEWS
#define NEWSRC ".newsrc"
/* #define BERKNAME "ARPAVAX" /* name of local host on Berknet */
#define LINES 512 /* maximum no. of lines in .newsrc */
#define NEGCHAR '!' /* newsgroup negation character */
#define DEADTIME 45 /* no. of seconds to wait on deadlock */
#define FMETA '%' /* file meta-character for c option */
#define SYSPATH "PATH=/local/bin:/bin:/usr/bin" /* default, secure, vanilla path */
#define LNCNT 16 /* Articles with > LNCNT lines go through pager */
/* Things you probably won't want to change */
#define SNLN 8 /* max significant characters in sysname */
#define PROTO 'A' /* old protocol name */
#define NETCHRS "!:.@^%"/* Punct. chars used for various networks */
#define TRUE 1 /* boolean true */
#define FALSE 0 /* boolean false */
#define NGFSIZ 5000 /* legal newsgroup file size */
#define NGDELIM ',' /* delimit character in news group line */
!E!O!F!
cat > lib/dir.c <<\!E!O!F!
#include "config.h"
#if BSDREL < 42
#include <sys/types.h>
#include <sys/param.h>
#include "ndir.h"
/*
* open a directory.
*/
DIR *
opendir(name)
char *name;
{
register DIR *dirp;
register int fd;
char *malloc();
if ((fd = open(name, 0)) == -1)
return NULL;
if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
close (fd);
return NULL;
}
dirp->dd_fd = fd;
dirp->dd_nleft = 0;
return dirp;
}
/*
* close a directory.
*/
void
closedir(dirp)
register DIR *dirp;
{
close(dirp->dd_fd);
free(dirp);
}
/*
* read an old style directory entry and present it as a new one
*/
#define ODIRSIZ 14
struct olddirect {
ino_t od_ino;
char od_name[ODIRSIZ];
};
/*
* get next entry in a directory.
*/
struct direct *
readdir(dirp)
register DIR *dirp;
{
register struct olddirect *dp;
static struct direct dir;
for (;;) {
if ((dirp->dd_nleft -= sizeof(struct olddirect)) < 0) {
dirp->dd_nleft = read(dirp->dd_fd, dirp->dd_buf,
DIRBLKSIZ);
if (dirp->dd_nleft <= 0)
return NULL;
dirp->dd_nextc = dirp->dd_buf;
}
dp = (struct olddirect *) dirp->dd_nextc;
dirp->dd_nextc += sizeof(struct olddirect);
if (dp->od_ino == 0)
continue;
dir.d_ino = dp->od_ino;
strncpy(dir.d_name, dp->od_name, ODIRSIZ + 1);
dir.d_namlen = strlen(dir.d_name);
return (&dir);
}
}
#endif
!E!O!F!
cat > lib/dirname.c <<\!E!O!F!
#include "defs.h"
#include "libextern.h"
char *
dirname(ngname, rbuf)
char *ngname;
char rbuf[FPATHLEN];
{
register char *p;
sprintf(rbuf, "%s/%s", SPOOL, ngname);
for (p=rbuf+strlen(SPOOL); *p; p++)
if (*p == '.')
*p = '/';
return rbuf;
}
!E!O!F!
cat > lib/doc.h <<\!E!O!F!
.na
Newsgroups may be refered to by name or my number.
The name is identical across all machines,
the number is specific to a particular machine.
Articles are refered to by message id, by number in newsgroup,
or by offset into data base.
The message id is the same on all machines.
The number is specific to a given machine.
The offset into the data base is specific to a particular
machine and a particular open call to the data base.
(When expire runs, it moves the article records.
A program which has the data base open will continue
to use the old data base, however, so that the same offsets
will still work.)
The article data base contains a record for each article.
It consists of a single file divided into several sections.
First is the header, which gives the size of the other sections.
Second is a hash table for message ids.
Third is a hash table of reference lines which is used to deal with
orphaned articles.
Fourth is a table of pointers to newsgroup chains.
All the articles in a newsgroup are connected by a singly linked list.
Finally, the article records appear.
There is one article record for each article.
!E!O!F!
cat > lib/findgroup.c <<\!E!O!F!
#include "defs.h"
#include "str.h"
#include "newsrc.h"
struct ngentry *
findgroup(name)
register char *name ;
{
register struct ngentry *ngp ;
extern int maxng ;
for (ngp = ngtable; ngp < ngtable + MAXGROUPS ; ngp++) {
if (ngp->ng_name && equal(ngp->ng_name, name))
return ngp ;
}
return 0 ;
}
!E!O!F!
cat > lib/ftime.c <<\!E!O!F!
#include "config.h"
#if BSDREL < 7
static char *SccsId = "@(#)ftime.c 2.3 3/3/83";
#include <sys/types.h>
struct timeb
{
time_t time;
unsigned short millitm;
short timezone;
short dstflag;
};
extern long timezone;
extern int daylight;
ftime(tp)
struct timeb *tp;
{
long t;
tzset(); /* be sure time zone info set */
time(&t);
tp->time = t;
tp->millitm = 0;
tp->timezone = timezone/60;
tp->dstflag = daylight;
}
#endif
!E!O!F!
cat > lib/genafopen.c <<\!E!O!F!
#include <stdio.h>
#include "af.h"
int affd ; /* artfile file descriptor */
struct afheader afhd ; /* artfile header */
genafopen(file, mode)
char *file, *mode ;
{
int omode = mode[1] ? 2 : 0 ;
if ((affd = open(file, omode)) < 0
&& (sleep(2), affd = open(file, omode)) < 0)
xerror("can't open %s", file) ;
if (read(affd, (char *)&afhd, sizeof(afhd)) != sizeof afhd)
xerror("can't read data base header") ;
if (afhd.af_magic != AF_MAGIC)
xerror("bad data base file") ;
if (afhd.af_version != AF_VERSION)
xerror("Version of article data base is wrong") ;
}
!E!O!F!
cat > lib/genmakefile <<\!E!O!F!
. makedefs
exec > makefile
cat <<\!
# makefile for rlib 1/4/85
!
cat makedefs
cat <<\!
CFLAGS = $(DEBUG)
DEBUG = -O
MAKE = make
RLIB = aflock.o afopen.o cancel.o cgtdate.o dir.o dirname.o\
genafopen.o getadate.o getdate.o ftime.o gethead.o getopt.o\
getuser.o hfgets.o hfree.o hxchg.o isadmin.o isre.o launder.o\
lookup.o ngchain.o ngmatch.o openrc.o pgetuser.o read.o\
replyname.o rewinddir.o rmnf.o readinrc.o roptions.o titmat.o\
write.o setupgrp.o addrc.o allgroups.o findgroup.o gfopen.o\
makehimask.o nextgrp.o prevgrp.o bfr.o bcopy.o bzero.o ckfopen.o\
getaddr.o hash.o lcase.o nsavestr.o nstrip.o prefix.o process.o\
rename.o savestr.o ckmalloc.o scopyn.o strpbrk.o strcspn.o\
strspn.o strtok.o tomsgid.o
all: setuptime makefile rlib.a cgtdate rpathinit.o newer
install: all
/bin/cp cgtdate $(LIBDIR)/cgtdate
setuptime: setup config
sh setup
makefile: genmakefile makedefs
genmakefile
@echo 'Makefile changed. Restart make program.'
@sh -c 'exit 22'
rlib.a: $(RLIB)
rm -f $@
ar rc $@ $(RLIB)
!
if test $BSDREL -gt 7
then echo " ranlib \$@"
fi
: Add more assembly language routines when they have been tested.
case $CPU in
pdp11) files="" suffix=pdp ;;
vax) files="scopyn" suffix=vax ;;
u3b) files="bcopy bzero scopyn strpbrk" suffix=u3b ;;
*) files=
esac
for x in $files
do cat <<!
$x.o: $x.$suffix
\$(AS) -o $x.o $x.$suffix
!
done
cat <<\!
rpathinit.o: mypathinit.c defs.h newsdefs.h $(FRC)
$(CC) -c $(CFLAGS) mypathinit.c
mv mypathinit.o rpathinit.o
genafopen.o lock.o lookup.o ngchain.o read.o: af.h artfile.h
readinrc.o setupgrp.o: artfile.h
addrc.o nextgrp.o prevgrp.o readinrc.o setupgrp.o: newsrc.h
allgroups.o readinrc.o: ng.h
cancel.o gethead.o hfree.o hxchg.o: arthead.h
$(RLIB): $(FRC)
cgtdate: cgtdatecmd.o cgtdate.o getadate.o getdate.o
$(CC) $(LFLAGS) -o $@ cgtdatecmd.o rlib.a
newer: newer.c
$(CC) -o $@ newer.c
FRC:
!
!E!O!F!
chmod +x lib/genmakefile
cat > lib/getadate.c <<\!E!O!F!
/*
* getadate - get arpa date.
*
* This routine takes a character character string containing a
* date-time in the format specified in RFC 822 and converts it
* to UNIX internal format. The components of the date are left
* in the global tm structure arpadtm. Getarpad returns -1L if
* the argument is syntactically incorrect.
*/
#include "config.h"
#if BSDREL == 42
#include <sys/time.h>
#else
#include <time.h>
#endif
#include <ctype.h>
#define HR 3600
#define DAY (24L*HR)
struct tm adatetm ;
static int lookup(), getdig(), skipbl() ;
static char *d ;
static char *days[] = {"sun", "mon", "tue", "wed", "thu", "fri", "sat", 0} ;
static char *months[] = {"jan", "feb", "mar", "apr", "may", "jun",
"jul", "aug", "sep", "oct", "nov", "dec", 0} ;
static char *zones[] =
{"ut", "gmt", "est", "edt", "cst", "cdt", "mst", "mdt", "pst", "pdt",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "k", "l", "m",
"n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z",
/* the remaining time zones are not legal according to RFC822 */
"yst", "ydt", "hst", "hdt",
"aest", "aesst", "acst", "acsst", "awst", 0} ;
static long zoffset[] =
{0, 0, 5*HR, 4*HR, 6*HR, 5*HR, 7*HR, 6*HR, 8*HR, 7*HR,
1*HR,2*HR,3*HR,4*HR,5*HR,6*HR,7*HR,8*HR,9*HR,10*HR,11*HR,12*HR,
-1*HR, -2*HR, -3*HR, -4*HR, -5*HR, -6*HR,
-7*HR, -8*HR, -9*HR,-10*HR,-11*HR,-12*HR, 0,
/* the remaining time zones are not legal according to RFC822 */
9*HR, 8*HR, 10*HR, 9*HR,
-10*HR, -11*HR, -9*HR-HR/2,-10*HR-HR/2,-8*HR, 0} ;
static int mon[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334} ;
long
getadate(date)
register char *date ;
{
int i ;
int oh ;
long tim ;
long offset ;
d = date ;
if ((adatetm.tm_wday = lookup(days)) >= 0) {
if (getch(',') < 0)
bad: return -1L ;
}
skipbl() ;
if (! isdigit(*d))
goto bad ;
adatetm.tm_mday = *d++ - '0' ;
if (isdigit(*d))
adatetm.tm_mday = adatetm.tm_mday * 10 + *d++ - '0' ;
if (*d == '-') /* ARPA spec doesn't permit this */
d++ ;
if ((adatetm.tm_mon = lookup(months)) < 0)
goto bad ;
getch('-') ; /* ARPA spec doesn't permit this */
if ((adatetm.tm_year = getdig()) < 0)
goto bad ;
skipbl() ;
if ((adatetm.tm_hour = getdig()) < 0)
goto bad ;
if (getch(':') < 0)
goto bad ;
if ((adatetm.tm_min = getdig()) < 0)
goto bad ;
if (getch(':') < 0)
adatetm.tm_sec = 0 ;
else if ((adatetm.tm_sec = getdig()) < 0)
goto bad ;
if (getch('+') >= 0) {
offset = 60 ;
numtz: if ((oh = getdig()) < 0
|| (i = getdig()) < 0)
goto bad ;
offset *= 60 * oh + i ;
} else if (getch('-') >= 0) {
offset = -60 ;
goto numtz ;
} else if ((i = lookup(zones)) >= 0)
offset = zoffset[i] ;
else
goto bad ;
/* now calculate the time */
adatetm.tm_yday = mon[adatetm.tm_mon] + adatetm.tm_mday - 1 ;
if ((adatetm.tm_year & 03) == 0 && adatetm.tm_mon >= 2)
adatetm.tm_yday++ ;
tim = adatetm.tm_sec + 60 * adatetm.tm_min + 3600L * adatetm.tm_hour
+ offset + DAY * adatetm.tm_yday ;
for (i = adatetm.tm_year ; --i >= 70 ; )
tim += (i & 03) == 0? 366 * DAY : 365 * DAY ;
return tim ;
}
static int
lookup(ltab)
char **ltab ;
{
char tok[20] ;
register char *dp ;
register char *tp ;
register char **lp ;
dp = d ;
tp = tok ;
while (isspace(*dp))
dp++ ;
for (;;) {
if (isupper(*dp))
*tp++ = tolower(*dp) ;
else if (islower(*dp))
*tp++ = *dp ;
else
break ;
if (tp >= &tok[20])
return -1 ;
dp++ ;
}
if (dp == d)
return -1 ;
*tp = '\0' ;
for (lp = ltab ; *lp ; lp++) {
if (strcmp(*lp, tok) == 0) {
d = dp ;
return lp - ltab ;
}
}
return -1 ;
}
static int
getdig() {
register char *p ;
p = d ;
if (! isdigit(*p) || ! isdigit(*++p))
return -1 ;
d += 2 ;
return 10 * p[-1] + p[0] - (10 * '0' + '0') ;
}
static
skipbl() {
while (isspace(*d))
d++ ;
}
static int
getch(c) {
skipbl() ;
if (*d != c)
return -1 ;
d++ ;
skipbl() ;
return 0 ;
}
!E!O!F!
cat > lib/getaddr.c <<\!E!O!F!
/*
* Get the machine address of a person, stripping off the real name.
*/
#include <stdio.h>
#include "config.h"
#include "defs.h"
char *
getaddr(full, mach)
char full[] ;
char mach[NAMELEN] ;
{
register char *p, *q, *r ;
char *index(), *rindex();
p = full ;
if ((q = index(p, '(')) == NULL)
q = p + strlen(p) ;
if ((p = index(full, '<')) != NULL && p < q && (r = rindex(p, '>')) != NULL) {
p++ ;
q = r ;
} else
p = full ;
while (*p == ' ')
p++ ;
while (--q > p && *q == ' ') ;
if (q > p + NAMELEN - 1)
q = p + NAMELEN - 1 ;
r = mach ;
while (p <= q)
*r++ = *p++ ;
*r = '\0' ;
return mach ;
}
!E!O!F!
cat > lib/getdate.y <<\!E!O!F!
%token ID MONTH DAY MERIDIAN NUMBER UNIT MUNIT SUNIT ZONE DAYZONE AGO
%{
/* Steven M. Bellovin (unc!smb) */
/* Dept. of Computer Science */
/* University of North Carolina at Chapel Hill */
/* @(#)getdate.y 2.6 4/20/84 */
#include <sys/types.h>
#include "config.h"
#if BSDREL < 7
struct timeb
{
time_t time;
unsigned short millitm;
short timezone;
short dstflag;
};
#else
#include <sys/timeb.h>
#endif
#include <ctype.h>
#include <time.h>
#define NULL 0
#define daysec (24L*60L*60L)
static int timeflag, zoneflag, dateflag, dayflag, relflag;
static time_t relsec, relmonth;
static int hh, mm, ss, merid, daylight;
static int dayord, dayreq;
static int month, day, year;
static int ourzone;
#define AM 1
#define PM 2
#define DAYLIGHT 1
#define STANDARD 2
#define MAYBE 3
%}
%%
timedate: /* empty */
| timedate item;
item: tspec =
{timeflag++;}
| zone =
{zoneflag++;}
| dtspec =
{dateflag++;}
| dyspec =
{dayflag++;}
| rspec =
{relflag++;}
| nspec;
nspec: NUMBER =
{if (timeflag && dateflag && !relflag) year = $1;
else {timeflag++;hh = $1/100;mm = $1%100;ss = 0;merid = 24;}};
tspec: NUMBER MERIDIAN =
{hh = $1; mm = 0; ss = 0; merid = $2;}
| NUMBER ':' NUMBER =
{hh = $1; mm = $3; merid = 24;}
| NUMBER ':' NUMBER MERIDIAN =
{hh = $1; mm = $3; merid = $4;}
| NUMBER ':' NUMBER ':' NUMBER =
{hh = $1; mm = $3; ss = $5; merid = 24;}
| NUMBER ':' NUMBER ':' NUMBER MERIDIAN =
{hh = $1; mm = $3; ss = $5; merid = $6;};
zone: ZONE =
{ourzone = $1; daylight = STANDARD;}
| DAYZONE =
{ourzone = $1; daylight = DAYLIGHT;};
dyspec: DAY =
{dayord = 1; dayreq = $1;}
| DAY ',' =
{dayord = 1; dayreq = $1;}
| NUMBER DAY =
{dayord = $1; dayreq = $2;};
dtspec: NUMBER '/' NUMBER =
{month = $1; day = $3;}
| NUMBER '/' NUMBER '/' NUMBER =
{month = $1; day = $3; year = $5;}
| MONTH NUMBER =
{month = $1; day = $2;}
| MONTH NUMBER ',' NUMBER =
{month = $1; day = $2; year = $4;}
| NUMBER MONTH =
{month = $2; day = $1;}
| NUMBER MONTH NUMBER =
{month = $2; day = $1; year = $3;};
rspec: NUMBER UNIT =
{relsec += 60L * $1 * $2;}
| NUMBER MUNIT =
{relmonth += $1 * $2;}
| NUMBER SUNIT =
{relsec += $1;}
| UNIT =
{relsec += 60L * $1;}
| MUNIT =
{relmonth += $1;}
| SUNIT =
{relsec++;}
| rspec AGO =
{relsec = -relsec; relmonth = -relmonth;};
%%
static int mdays[12] =
{31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
#define epoch 1970
extern struct tm *localtime();
time_t dateconv(mm, dd, yy, h, m, s, mer, zone, dayflag)
int mm, dd, yy, h, m, s, mer, zone, dayflag;
{
time_t tod, jdate;
register int i;
time_t timeconv();
if (yy < 0) yy = -yy;
if (yy < 100) yy += 1900;
mdays[1] = 28 + (yy%4 == 0);
if (yy < epoch || yy > 1999 || mm < 1 || mm > 12 ||
dd < 1 || dd > mdays[--mm]) return (-1);
jdate = dd-1;
for (i=0; i<mm; i++) jdate += mdays[i];
for (i = epoch; i < yy; i++) jdate += 365 + (i%4 == 0);
jdate *= daysec;
jdate += zone * 60L;
if ((tod = timeconv(h, m, s, mer)) < 0) return (-1);
jdate += tod;
if (dayflag==DAYLIGHT || (dayflag==MAYBE&&localtime(&jdate)->tm_isdst))
jdate += -1*60*60;
return (jdate);
}
time_t dayconv(ord, day, now) int ord, day; time_t now;
{
register struct tm *loctime;
time_t tod;
time_t daylcorr();
tod = now;
loctime = localtime(&tod);
tod += daysec * ((day - loctime->tm_wday + 7) % 7);
tod += 7*daysec*(ord<=0?ord:ord-1);
return daylcorr(tod, now);
}
time_t timeconv(hh, mm, ss, mer) register int hh, mm, ss, mer;
{
if (mm < 0 || mm > 59 || ss < 0 || ss > 59) return (-1);
switch (mer) {
case AM: if (hh < 1 || hh > 12) return(-1);
return (60L * ((hh%12)*60L + mm)+ss);
case PM: if (hh < 1 || hh > 12) return(-1);
return (60L * ((hh%12 +12)*60L + mm)+ss);
case 24: if (hh < 0 || hh > 23) return (-1);
return (60L * (hh*60L + mm)+ss);
default: return (-1);
}
}
time_t monthadd(sdate, relmonth) time_t sdate, relmonth;
{
struct tm *ltime;
time_t dateconv();
time_t daylcorr();
int mm, yy;
if (relmonth == 0) return 0;
ltime = localtime(&sdate);
mm = 12*ltime->tm_year + ltime->tm_mon + relmonth;
yy = mm/12;
mm = mm%12 + 1;
return daylcorr(dateconv(mm, ltime->tm_mday, yy, ltime->tm_hour,
ltime->tm_min, ltime->tm_sec, 24, ourzone, MAYBE), sdate);
}
time_t daylcorr(future, now) time_t future, now;
{
int fdayl, nowdayl;
nowdayl = (localtime(&now)->tm_hour+1) % 24;
fdayl = (localtime(&future)->tm_hour+1) % 24;
return (future-now) + 60L*60L*(nowdayl-fdayl);
}
static char *lptr;
yylex()
{
extern int yylval;
int sign;
register char c;
register char *p;
char idbuf[20];
int pcnt;
for (;;) {
while (isspace(*lptr)) lptr++;
if (isdigit(c = *lptr) || c == '-' || c == '+') {
if (c== '-' || c == '+') {
if (c=='-') sign = -1;
else sign = 1;
if (!isdigit(*++lptr)) {
/* yylval = sign; return (NUMBER); */
return yylex(); /* skip the '-' sign */
}
} else sign = 1;
yylval = 0;
while (isdigit(c = *lptr++)) yylval = 10*yylval + c - '0';
yylval *= sign;
lptr--;
return (NUMBER);
} else if (isalpha(c)) {
p = idbuf;
while (isalpha(c = *lptr++) || c=='.')
*p++ = c;
*p = '\0';
lptr--;
return (lookup(idbuf));
}
else if (c == '(') {
pcnt = 0;
do {
c = *lptr++;
if (c == '\0') return(c);
else if (c == '(') pcnt++;
else if (c == ')') pcnt--;
} while (pcnt > 0);
}
else return (*lptr++);
}
}
struct table {
char *name;
int type, value;
};
struct table mdtab[] = {
{"January", MONTH, 1},
{"February", MONTH, 2},
{"March", MONTH, 3},
{"April", MONTH, 4},
{"May", MONTH, 5},
{"June", MONTH, 6},
{"July", MONTH, 7},
{"August", MONTH, 8},
{"September", MONTH, 9},
{"Sept", MONTH, 9},
{"October", MONTH, 10},
{"November", MONTH, 11},
{"December", MONTH, 12},
{"Sunday", DAY, 0},
{"Monday", DAY, 1},
{"Tuesday", DAY, 2},
{"Tues", DAY, 2},
{"Wednesday", DAY, 3},
{"Wednes", DAY, 3},
{"Thursday", DAY, 4},
{"Thur", DAY, 4},
{"Thurs", DAY, 4},
{"Friday", DAY, 5},
{"Saturday", DAY, 6},
{0, 0, 0}};
#define HRS *60
#define HALFHR 30
struct table mztab[] = {
{"a.m.", MERIDIAN, AM},
{"am", MERIDIAN, AM},
{"p.m.", MERIDIAN, PM},
{"pm", MERIDIAN, PM},
{"nst", ZONE, 3 HRS + HALFHR}, /* Newfoundland */
{"n.s.t.", ZONE, 3 HRS + HALFHR},
{"ast", ZONE, 4 HRS}, /* Atlantic */
{"a.s.t.", ZONE, 4 HRS},
{"adt", DAYZONE, 4 HRS},
{"a.d.t.", DAYZONE, 4 HRS},
{"est", ZONE, 5 HRS}, /* Eastern */
{"e.s.t.", ZONE, 5 HRS},
{"edt", DAYZONE, 5 HRS},
{"e.d.t.", DAYZONE, 5 HRS},
{"cst", ZONE, 6 HRS}, /* Central */
{"c.s.t.", ZONE, 6 HRS},
{"cdt", DAYZONE, 6 HRS},
{"c.d.t.", DAYZONE, 6 HRS},
{"mst", ZONE, 7 HRS}, /* Mountain */
{"m.s.t.", ZONE, 7 HRS},
{"mdt", DAYZONE, 7 HRS},
{"m.d.t.", DAYZONE, 7 HRS},
{"pst", ZONE, 8 HRS}, /* Pacific */
{"p.s.t.", ZONE, 8 HRS},
{"pdt", DAYZONE, 8 HRS},
{"p.d.t.", DAYZONE, 8 HRS},
{"yst", ZONE, 9 HRS}, /* Yukon */
{"y.s.t.", ZONE, 9 HRS},
{"ydt", DAYZONE, 9 HRS},
{"y.d.t.", DAYZONE, 9 HRS},
{"hst", ZONE, 10 HRS}, /* Hawaii */
{"h.s.t.", ZONE, 10 HRS},
{"hdt", DAYZONE, 10 HRS},
{"h.d.t.", DAYZONE, 10 HRS},
{"bst", ZONE, 11 HRS}, /* Bering */
{"b.s.t.", ZONE, 11 HRS},
{"bdt", DAYZONE, 11 HRS},
{"b.d.t.", DAYZONE, 11 HRS},
{"gmt", ZONE, 0 HRS},
{"g.m.t.", ZONE, 0 HRS},
{"aest", ZONE, -10 HRS}, /* Australian Eastern Time */
{"a.e.s.t.", ZONE, -10 HRS},
{"aesst", DAYZONE, -10 HRS}, /* Australian Eastern Summer Time */
{"a.e.s.s.t.", DAYZONE, -10 HRS},
{"acst", ZONE, -(9 HRS + HALFHR)}, /* Australian Central Time */
{"a.c.s.t.", ZONE, -(9 HRS + HALFHR)},
{"acsst", DAYZONE, -(9 HRS + HALFHR)}, /* Australian Central Summer */
{"a.c.s.s.t.", DAYZONE, -(9 HRS + HALFHR)},
{"awst", ZONE, -8 HRS}, /* Australian Western Time */
{"a.w.s.t.", ZONE, -8 HRS}, /* (no daylight time there, I'm told */
{0, 0, 0}};
struct table unittb[] = {
{"year", MUNIT, 12},
{"month", MUNIT, 1},
{"fortnight", UNIT, 14*24*60},
{"week", UNIT, 7*24*60},
{"day", UNIT, 1*24*60},
{"hour", UNIT, 60},
{"minute", UNIT, 1},
{"min", UNIT, 1},
{"second", SUNIT, 1},
{"sec", SUNIT, 1},
{0, 0, 0}};
struct table othertb[] = {
{"tomorrow", UNIT, 1*24*60},
{"yesterday", UNIT, -1*24*60},
{"today", UNIT, 0},
{"now", UNIT, 0},
{"last", NUMBER, -1},
{"this", UNIT, 0},
{"next", NUMBER, 2},
{"first", NUMBER, 1},
/* {"second", NUMBER, 2}, */
{"third", NUMBER, 3},
{"fourth", NUMBER, 4},
{"fifth", NUMBER, 5},
{"sixth", NUMBER, 6},
{"seventh", NUMBER, 7},
{"eigth", NUMBER, 8},
{"ninth", NUMBER, 9},
{"tenth", NUMBER, 10},
{"eleventh", NUMBER, 11},
{"twelfth", NUMBER, 12},
{"ago", AGO, 1},
{0, 0, 0}};
struct table milzone[] = {
{"a", ZONE, 1 HRS},
{"b", ZONE, 2 HRS},
{"c", ZONE, 3 HRS},
{"d", ZONE, 4 HRS},
{"e", ZONE, 5 HRS},
{"f", ZONE, 6 HRS},
{"g", ZONE, 7 HRS},
{"h", ZONE, 8 HRS},
{"i", ZONE, 9 HRS},
{"k", ZONE, 10 HRS},
{"l", ZONE, 11 HRS},
{"m", ZONE, 12 HRS},
{"n", ZONE, -1 HRS},
{"o", ZONE, -2 HRS},
{"p", ZONE, -3 HRS},
{"q", ZONE, -4 HRS},
{"r", ZONE, -5 HRS},
{"s", ZONE, -6 HRS},
{"t", ZONE, -7 HRS},
{"u", ZONE, -8 HRS},
{"v", ZONE, -9 HRS},
{"w", ZONE, -10 HRS},
{"x", ZONE, -11 HRS},
{"y", ZONE, -12 HRS},
{"z", ZONE, 0 HRS},
{0, 0, 0}};
lookup(id) char *id;
{
#define gotit (yylval=i->value, i->type)
#define getid for(j=idvar, k=id; *j++ = *k++; )
char idvar[20];
register char *j, *k;
register struct table *i;
int abbrev;
getid;
if (strlen(idvar) == 3) abbrev = 1;
else if (strlen(idvar) == 4 && idvar[3] == '.') {
abbrev = 1;
idvar[3] = '\0';
}
else abbrev = 0;
if (islower(*idvar)) *idvar = toupper(*idvar);
for (i = mdtab; i->name; i++) {
k = idvar;
for (j = i->name; *j++ == *k++;) {
if (abbrev && j==i->name+3) return gotit;
if (j[-1] == 0) return gotit;
}
}
getid;
for (i = mztab; i->name; i++)
if (strcmp(i->name, idvar) == 0) return gotit;
for (j = idvar; *j; j++) if (isupper(*j)) *j = tolower(*j);
for (i=mztab; i->name; i++)
if (strcmp(i->name, idvar) == 0) return gotit;
getid;
for (i=unittb; i->name; i++)
if (strcmp(i->name, idvar) == 0) return gotit;
if (idvar[strlen(idvar)-1] == 's') idvar[strlen(idvar)-1] = '\0';
for (i=unittb; i->name; i++)
if (strcmp(i->name, idvar) == 0) return gotit;
getid;
for (i = othertb; i->name; i++)
if (strcmp(i->name, idvar) == 0) return gotit;
getid;
if (strlen(idvar) == 1 && isalpha(*idvar)) {
if (isupper(*idvar)) *idvar = tolower(*idvar);
for (i = milzone; i->name; i++)
if (strcmp(i->name, idvar) == 0) return gotit;
}
return(ID);
}
time_t getdate(p, now) char *p; struct timeb *now;
{
#define mcheck(f) if (f>1) err++
time_t monthadd();
int err;
struct tm *lt;
struct timeb ftz;
time_t sdate, tod;
lptr = p;
if (now == ((struct timeb *) NULL)) {
now = &ftz;
ftime(&ftz);
}
lt = localtime(&now->time);
year = lt->tm_year;
month = lt->tm_mon+1;
day = lt->tm_mday;
relsec = 0; relmonth = 0;
timeflag=zoneflag=dateflag=dayflag=relflag=0;
ourzone = now->timezone;
daylight = MAYBE;
hh = mm = ss = 0;
merid = 24;
if (err = yyparse()) return (-1);
mcheck(timeflag);
mcheck(zoneflag);
mcheck(dateflag);
mcheck(dayflag);
if (err) return (-1);
if (dateflag || timeflag || dayflag) {
sdate = dateconv(month,day,year,hh,mm,ss,merid,ourzone,daylight);
if (sdate < 0) return -1;
}
else {
sdate = now->time;
if (relflag == 0)
sdate -= (lt->tm_sec + lt->tm_min*60 +
lt->tm_hour*(60L*60L));
}
sdate += relsec;
sdate += monthadd(sdate, relmonth);
if (dayflag && !dateflag) {
tod = dayconv(dayord, dayreq, sdate);
sdate += tod;
}
return sdate;
}
yyerror(s) char *s;
{}
!E!O!F!
echo Part 2 of 7 extracted.
More information about the Mod.sources
mailing list