[net.sources.bugs] uuhosts: extract and display mod.map.all

jay@unm-la.UUCP (01/05/85)

getmaps: get the lastest maps from mod.map.all
cc -O [-DLOG] -o getmaps getmaps.c
getmaps [-l logfile] [-g map_dir] [-s seq_file] [-a archive_dir]

This corrects a bug in Lee's earlier posting whereby the seq file
sometimes winds up with the wrong value, confusing next month's
extraction.  It borrows a few ideas from a similar fix sent to
Lee by ncr-tp!greg (Greg Noel).

The contextual diffs wound up about the same size as the source,
so here's the whole thing again.

> Gotta have libndir though. [ie, 4.2bsd with scandir()]
> 
> (Don't forget to strip the .signature at the end)

#ifndef	lint
char	*Rcsid = "$Header: getmaps.c,v 1.4 85/01/04 13:56:20 jay Exp $";
#endif

/*
 * getmaps
 *
 * Get the net maps from USENET as published by Karen and Mark Horton, in
 * "shar" format. Because of paranoia the sh is not used but instead a DFA
 * recognizing the appropriate commands.
 *
 * lee Ward		10/13/84
 */

#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>

char	*mapgrp = "/usr/spool/news/mod/map/news";
char	*mapdir = "/usr/lib/news/maps";
char	*seqfil = "/usr/lib/news/maps/.seq";
#ifdef	LOG
char	*logfil = "/usr/lib/news/maps/.log";
#endif	LOG

#ifdef	LOG
char	*usestr = "[-l logfil] [-g group] [-s seqfile] [-a archiv-dir]";

FILE	*logsd = NULL;

int	seqn, curn;

#else	LOG
char	*usestr = "[-g group] [-s seqfile] [-a archiv-dir]";
#endif	LOG

void	domaps(), myabort(), mkmaps(), getwrd();
#ifdef	LOG
void	log(), logtime();
#endif	LOG

main(argc, argv)
	int	argc;
	char	*argv[];
{
	int	x;
	FILE	*seqsd;

	for (x = 1; x < argc; x++) {
		if (*argv[x]++ != '-') {
			fprintf(stderr, "Bad usage\n");
			fprintf(stderr, "Usage: %s %s\n", argv[0], usestr);
			exit(-1);
		}
		switch (*argv[x]) {

#ifdef	LOG
		case 'l':
			logfil = argv[++x];
			break;
#endif	LOG
		case 'g':
			mapgrp = argv[++x];
			break;
		case 's':
			seqfil = argv[++x];
			break;
		case 'a':
			mapdir = argv[++x];
			break;
		default:
			fprintf(stderr, "Bad switch\n");
			fprintf(stderr, "Usage: %s %s\n", argv[0], usestr);
			exit(-1);
		}
	}

#ifdef	LOG
	logsd = fopen(logfil, "a");

	logtime("Start");
#endif	LOG

	if (chdir(mapdir) != 0)
		myabort("Could not change directory to %s", mapdir);

	if ((seqsd = fopen(seqfil, "r")) != NULL) {
		if (fscanf(seqsd, "%d", &seqn) != 1)
			myabort("Bad seq file");
		(void )fclose(seqsd);
	}
	if ((seqsd = fopen(seqfil, "a")) == NULL)
		myabort("Could not open seq file for writing");
	(void )fseek(seqsd, 0L, 0);

	domaps(mapgrp, seqn, seqsd);
	(void )fclose(seqsd);

#ifdef	LOG
	logtime("End");
#endif	LOG
}

void
domaps(grp, seqn, seqsd)
	char	*grp;
	FILE	*seqsd;
{
	char	nbuf[BUFSIZ], *nptr;
	struct direct **filst;
	int	nfils, x;
	struct stat stbuf;
	extern int scandir();
	int	numsort(), select();
	extern char *strcpy(), *strncat();

	if ((nfils = scandir(grp, &filst, select, numsort)) == -1)
		myabort("scandir failed");

	(void )strncpy(nbuf, grp, BUFSIZ-2);
	nptr = nbuf + strlen(nbuf);
	*nptr++ = '/';
	*nptr = NULL;
	nbuf[BUFSIZ-1] = NULL;
#ifdef	LOG
	log("Getting maps from %s", nbuf);
#endif	LOG

	for (x = 0; x < nfils; x++) {
		(void )strncpy(nptr, filst[x]->d_name,
		    BUFSIZ - (nptr - nbuf) - 1);
		if (stat(nbuf, &stbuf) != 0) {
#ifdef	LOG
			log("Could not stat %s", nbuf);
#endif	LOG
			continue;
		}
		if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
			continue;

		curn = atoi(filst[x]->d_name);
		mkmaps(nbuf);
		(void )fseek(seqsd, 0L, 0);
		(void )fprintf(seqsd, "%d\n", curn);
		(void )fflush(seqsd);
	}
}

void
mkmaps(file)
	char	*file;
{
#define	SEARCH		1
#define	INAMAP		2
#define	SKIPPING	3

	char	buf[BUFSIZ], tofil[BUFSIZ], delim[BUFSIZ];
	int	state = SEARCH, sizdel = 0;
	FILE	*isd, *osd;
	extern FILE *fopen();


	if ((isd = fopen(file, "r")) == NULL) {
#ifdef	LOG
		log("Could not open %s. Skipping...", file);
#endif	LOG
		return;
	}

#ifdef	LOG
	log("Unarchive %d", curn);
#endif	LOG
	while (fgets(buf, sizeof(buf) - 1, isd) != NULL) {
		buf[sizeof(buf)] = NULL;
		switch (state) {
		case SEARCH:
			if (gotcat(buf, tofil, BUFSIZ, delim, BUFSIZ)) {
				state = INAMAP;
				sizdel = strlen(delim);
				if ((osd = fopen(tofil, "w")) == NULL) {
#ifdef	LOG
					log("Could not open %s", tofil);
#endif	LOG
					state = SKIPPING;
				}
			}
			break;
		case SKIPPING:
		case INAMAP:
			if (strncmp(buf, delim, sizdel) == 0) {
				state = SEARCH;
				if (osd != NULL)
					(void )fclose(osd);
			}
			else if (osd != NULL)
				fputs(buf, osd);
			break;
		}
	}

#ifdef	LOG
	if (state != SEARCH)
		log("Read/sync error on %s", file);
#endif	LOG

	(void )fclose(isd);

#undef	SEARCH
#undef	INAMAP
#undef	SKIPPING
}

/*
 * gotcat
 *
 * Use a DFA to recognize
 *	cat << DELIM > OUT
 * or
 *	cat > OUT << DELIM
 *
 */

/* Transition table for the DFA */
int	ttbl[9][4] = {
		1,-1,-1,-1,
		-1,6,2,-1,
		-1,-1,-1,3,
		-1,4,-1,-1,
		-1,-1,-1,5,
		-1,-1,-1,-1,
		-1,-1,-1,7,
		-1,-1,8,-1,
		-1,-1,-1,5,
	};

gotcat(buf, tofil, tofilln, delim, delimln)
	char	*buf,
		*tofil,
		*delim;
	int	tofilln,
		delimln;
{
	int	state;
	char	*ptr;

	state = 0;			/* Start state */
	while (state != -1 && state != 5) {
		/* Eat up white */
		while (*buf != '\n' && (*buf == ' ' || *buf == '\t'))
			buf++;
		if (*buf == '>') {
			buf++;
			state = ttbl[state][1];
			continue;
		}
		if (*buf == '<' && *(buf + 1) == '<') {
			buf += 2;
			state = ttbl[state][2];
			continue;
		}
		if (*buf == 'c' && *(buf + 1) == 'a' && *(buf + 2) == 't') {
			buf += 3;
			state = ttbl[state][0];
			continue;
		}
		ptr = buf;
		while (*buf != '\n' && *buf != ' ' && *buf != '\t')
			buf++;
		if (state == 2 || state == 8)
			getwrd(ptr, buf, delim, delimln);
		else if (state == 6 || state == 4)
			getwrd(ptr, buf, tofil, tofilln);
		state = ttbl[state][3];
	}

	if (state == 5)
		return(1);
	return(0);
}

void
getwrd(fc, lc, buf, maxlen)
	char	*fc,
		*lc,
		*buf;
	int	maxlen;
{
	char	*ptr, *t1ptr, *t2ptr;

	maxlen--;
	maxlen = lc - fc > maxlen ? maxlen : lc - fc;
	ptr = buf;
	t1ptr = fc;
	while (maxlen-- != 0)
		*ptr++ = *t1ptr++;
	*ptr = NULL;

	/* Strip quotes */
	ptr = buf;
	while (*ptr != NULL) {
		if (*ptr == '\\' && (*(ptr + 1) == '\'' || *(ptr + 1) == '"'))
			ptr += 2;
		else if (*ptr == '\'' || *ptr == '"') {
			t1ptr = ptr;
			t2ptr = ptr + 1;
			while ((*t1ptr++ = *t2ptr++) != NULL)
				;
		} else
			ptr++;
	}
}
/*VARARGS1*/
void
myabort(s, a, b, c, d, e, f, g, h, i, j, k, l)
	char	*s;
{

#ifdef	LOG
	if (logsd != NULL) {
		fputs("ABORT - ", logsd);
		fprintf(logsd, s, a, b, c, d, e, f, g, h, i, j, k, l);
		(void )fputc('\n', logsd);
		logtime("End");
	}
#endif	LOG
	exit(-1);
}

#ifdef	LOG
/*VARARGS1*/
void
log(s, a, b, c, d, e, f, g, h, i, j, k, l)
	char	*s;
{

	if (logsd == NULL)
		return;
	fprintf(logsd, s, a, b, c, d, e, f, g, h, i, j, k, l);
	(void )fputc('\n', logsd);
	(void )fflush(logsd);
}

void
logtime(s)
	char	*s;
{
	time_t	clock;
	extern char *ctime();

	if (logsd == NULL)
		return;
	(void )time(&clock);
	fprintf(logsd, "%s %s", s, ctime(&clock));
	(void )fflush(logsd);
}
#endif	LOG

numsort(a, b)
	struct direct **a, **b;
{
	return(atoi((*a)->d_name) - atoi((*b)->d_name));
}

select(d)
	struct direct *d;
{
	char	*cp = d->d_name;
	int	i = 0;

	while (isdigit(*cp))
		i = 10 * i + *(cp++) - '0';
	return(*cp == NULL && i > seqn);
}
-- 
	Jay Plett
	{{ucbvax,gatech}!unmvax, lanl}!unm-la!jay

jsq@ut-sally.UUCP (John Quarterman) (01/07/85)

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by ut-sally!jsq on Sat Jan  5 14:41:10 CST 1985
# Contents:  README.2 uucpnews.sh patches
 
echo x - README.2
sed 's/^@//' > "README.2" <<'@//E*O*F README.2//'
This is a fix for my previous posting of uuhosts.
It contains a very minor fix to the display part of uuhosts.sh,
addition of some chmod commands to Makefile,
and uucpnews.sh to replace uucp.from.news.sh,
together with the appropriate changes to Makefile.

Uucpnews is a hack to fill out the UUCP map information
from mod.map.uucp with information from mod.map.news
so that pathalias can produce a usable routing database.

When this article is run through sh, it will first extract
the files README.2 and uucpnews.sh, then it will attempt
to use Larry Wall's patch program to modify uuhosts.sh
and Makefile.  If you don't have patch, you can make the
changes by hand.
@//E*O*F README.2//
chmod u=rw,g=r,o=r README.2
 
echo x - uucpnews.sh
sed 's/^@//' > "uucpnews.sh" <<'@//E*O*F uucpnews.sh//'
#!/bin/sh
#
#	This command, uucpnews, is a stopgap measure for use until
#	the UUCP map is complete.  It extracts mail information from the
#	USENET news map and uses it to fill in gaps in the UUCP mail map.
#
#	With no arguments, uucpnews changes to the news map directory,
#	$MAPS/$NEWSMAP, and uses all the files there as input.
#	(Alternatively, a list of file names may be given as arguments.)
#
#	It looks through the news map entries for ones with mail information,
#	extracts those into individual files in $DIR by host name, and later
#	copies all those for which there are not already host entries in
#	the mail map directory to the mail map directory,  $MAPS/UUCPMAP.
#	The new mail map files all have '-' appended so they can be easily
#	distinguished.  If uucpnews is run again, such $MAPS/UUCPMAP/*-
#	entries will be overwritten.
#
#	The temporary directory $DIR is removed after the command is done.
#
PATH=/usr/local:/usr/ucb:/bin:/usr/bin
umask 0002

LIB=/usr/local/lib
NEWS=$LIB/news
MAPS=$NEWS/maps
NEWSMAPGROUP=mod.map.news
UUCPMAPGROUP=mod.map.uucp
NEWSMAP=$NEWSMAPGROUP
UUCPMAP=$UUCPMAPGROUP

DIR=uucptmp

if [ $1x = x ]; then
	cd $MAPS/$NEWSMAP
	args=*
else
	args=$*
fi
mkdir $DIR

awk '
BEGIN {
	sbetween = 0; sinside = 1; state = sbetween;
	Date = "'"`date`"'";
	split (Date, date, " ");
	Mark = "uucpnews " date[3] " " date[2] " " date[6];
	dir = "'$DIR'";
}
state == sbetween && $1 == "Name:" {
	state = sinside;
	last = "";
	Name = "";
	System = "";
	Organization = "";
	Contact = "";
	Telephone = "";
	Postal = "";
	Address = "";
	News = "";
	Mail = "";
	Latlong = "";
	Remarks = "";
	Written = "";
	Comments = "";
}
state != sinside {
	next;
}
# { print $0; }
$1 == "Name:"		{ Name = $2;		next; }
$1 == "Organization:"	{
	Organization = $2;
	for (x = 3; x <= NF; x++)
		Organization = Organization " " $x;
	last = $1;
	next;
}
$1 == "Contact:"	{
	Contact = $2;
	for (x = 3; x <= NF; x++)
		Contact = Contact " " $x;
	last = $1;
	next;
}
$1 == "Phone:"		{
	Telephone = $2;
	for (x = 3; x <= NF; x++)
		Telephone = Telephone " " $x;
	last = $1;
	next;
}
$1 == "Postal-Address:"	{
	Postal = $2;
	for (x = 3; x <= NF; x++)
		Postal = Postal " " $x;
	last = $1;
	next;
}
$1 == "Electronic-Address:" {
	Address = $2;
	for (x = 3; x <= NF; x++)
		Address = Address " " $x;
	last = $1;
	next;
}
$1 == "News:"		{
	News = $2;
	for (x = 3; x <= NF; x++)
		News = News " " $x;
	last = $1;
	next;
}
(/^	/ || /^ /) && last == "News:" {
	for (x = 1; x <= NF; x++)
		News = News " " $x;
	next;
}
$1 == "Mail:"		{
	Mail = $2;
	for (x = 3; x <= NF; x++)
		Mail = Mail " " $x;
	last = $1;
	next;
}
(/^	/ || /^ /) && last == "Mail:" {
	for (x = 1; x <= NF; x++)
		Mail = Mail " " $x;
	next;
}
$1 == "Comments:"	{
	last = $1;
	if ($2 == "last" && $3 == "edited") {
		Written = $4;
		for (x = 5; x <= NF; x++)
			Written = Written " " $x;
		next;
	}
	Comments = $2;
	for (x = 3; x <= NF; x++)
		Comments = Comments " " $x;
	next;
}
/^$/ {
	state = sbetween;
	if (Mail == "")
		Mail = News;
	if (Mail == "")
		next;
	output = dir "/" Name;
	printf ("echo x - %s\n", output);
	printf ("cat > %s << '\''End-of-%s'\''\n", output, output);
	printf ("#N\t%s\n", Name);
	printf ("#S\t%s\n", System);
	printf ("#O\t%s\n", Organization);
	printf ("#C\t%s\n", Contact);
	printf ("#E\t%s\n", Address);
	printf ("#T\t%s\n", Telephone);
	printf ("#P\t%s\n", Postal);
	printf ("#L\t%s\n", Latlong);
	printf ("#R\t%s\n", Mark);
#	split (News, news, "");
#	printf ("#R\tNews:  %s", news[1]);
#	for (x = 2; news[x] != ""; x++) {
#		if ((x % 8) == 0)
#			printf ("\n\t");
#		else
#			printf (", ");
#		printf ("%s", news[x]);
#	}
#	printf ("\n");
	printf ("#W\t%s\n", Written);
	printf ("#\n");
	split (Mail, mail, " ");
	printf ("%s\t%s", Name, mail[1]);
	for (x = 2; mail[x] != ""; x++) {
		if ((x % 8) == 0)
			printf ("\n\t");
		else
			printf (", ");
		printf ("%s", mail[x]);
	}
	printf ("\n");
	if (Comments != "") {
		printf ("#\n");
		printf ("#%s\n", Comments);
	}
	printf ("\n");
	printf ("End-of-%s\n", output);
	next;
}
' $args | sh

cd $DIR
for f in *
do
	there=$MAPS/$UUCPMAP/$f
	if [ -r ${there} ]; then
		echo ${there}
		continue
	fi
	if [ -r ${there}. ]; then
		echo ${there}.
		continue
	fi
	if [ -r ${there}% ]; then
		echo ${there}%
		continue
	fi
#	if [ -r ${there}- ]; then
#		echo ${there}-
#		continue
#	fi
	echo new ${there}-
	mv $f ${there}-
done
cd ..
rm -rf $DIR
@//E*O*F uucpnews.sh//
chmod u=r,g=r,o=r uucpnews.sh
 
echo x - j/z
patch <<'@//E*O*F patches/'
diff -c -r ./Makefile ../Makefile
*** ./Makefile	Sat Jan  5 14:28:49 1985
--- ../Makefile	Mon Dec 17 06:31:20 1984
***************
*** 7,14
  # The maps from mod.map.all are under this directory.
  MAPS=$(NEWS)/maps
  
! SOURCES=uuhosts.sh mapsh.c uucp.from.news.sh
! ALL=uuhosts mapsh uucp.from.news
  
  all: $(ALL)
  

--- 7,14 -----
  # The maps from mod.map.all are under this directory.
  MAPS=$(NEWS)/maps
  
! SOURCES=uuhosts.sh mapsh.c uucpnews.sh
! ALL=uuhosts mapsh uucpnews
  
  all: $(ALL)
  
***************
*** 16,21
  	sed -e \
  's%^LIB=.*$$%LIB=$(LIB)%;s%^NEWS=.*$$%NEWS=$(NEWS)%;s%^MAPS=.*$$%MAPS=$(MAPS)%'\
   uuhosts.sh > uuhosts
  
  mapsh: mapsh.c
  	$(CC) -o mapsh -DMAPS=\"$(MAPS)\" mapsh.c

--- 16,22 -----
  	sed -e \
  's%^LIB=.*$$%LIB=$(LIB)%;s%^NEWS=.*$$%NEWS=$(NEWS)%;s%^MAPS=.*$$%MAPS=$(MAPS)%'\
   uuhosts.sh > uuhosts
+ 	chmod +x uuhosts
  
  mapsh: mapsh.c
  	$(CC) -o mapsh -DMAPS=\"$(MAPS)\" mapsh.c
***************
*** 20,26
  mapsh: mapsh.c
  	$(CC) -o mapsh -DMAPS=\"$(MAPS)\" mapsh.c
  
! uucp.from.news: uucp.from.news.sh
  	sed -e \
  's%^LIB=.*$$%LIB=$(LIB)%;s%^NEWS=.*$$%NEWS=$(NEWS)%;s%^MAPS=.*$$%MAPS=$(MAPS)%'\
   uucp.from.news.sh > uucp.from.news

--- 21,27 -----
  mapsh: mapsh.c
  	$(CC) -o mapsh -DMAPS=\"$(MAPS)\" mapsh.c
  
! uucpnews: uucpnews.sh
  	sed -e \
  's%^LIB=.*$$%LIB=$(LIB)%;s%^NEWS=.*$$%NEWS=$(NEWS)%;s%^MAPS=.*$$%MAPS=$(MAPS)%'\
   uucpnews.sh > uucpnews
***************
*** 23,29
  uucp.from.news: uucp.from.news.sh
  	sed -e \
  's%^LIB=.*$$%LIB=$(LIB)%;s%^NEWS=.*$$%NEWS=$(NEWS)%;s%^MAPS=.*$$%MAPS=$(MAPS)%'\
!  uucp.from.news.sh > uucp.from.news
  
  install: mapsh
  	cp uuhosts /usr/local/uuhosts

--- 24,31 -----
  uucpnews: uucpnews.sh
  	sed -e \
  's%^LIB=.*$$%LIB=$(LIB)%;s%^NEWS=.*$$%NEWS=$(NEWS)%;s%^MAPS=.*$$%MAPS=$(MAPS)%'\
!  uucpnews.sh > uucpnews
! 	chmod +x uucpnews
  
  install: mapsh
  	cp uuhosts /usr/local/uuhosts
diff -c -r ./uuhosts.sh ../uuhosts.sh
*** ./uuhosts.sh	Sat Jan  5 14:28:53 1985
--- ../uuhosts.sh	Tue Dec 18 09:18:13 1984
***************
*** 1,5
  #!/bin/sh
! # '@(#) uuhosts.sh 1.39 84/12/15'
  
  # PATH will have to be adjusted for non-BSD systems.
  PATH=/usr/local:/usr/ucb:/bin:/usr/bin

--- 1,5 -----
  #!/bin/sh
! # '@(#) uuhosts.sh 1.40 84/12/18'
  
  # PATH will have to be adjusted for non-BSD systems.
  PATH=/usr/local:/usr/ucb:/bin:/usr/bin
***************
*** 221,227
  			echo '
  USENET news host information:'
  			sed -n -e "/^Name:[ 	]*${arg}/,/^$/p" \
! 				`$look $lookopt$arg Index | awk '{print $2}'`
  		done
  		exit 0
  	;;

--- 221,227 -----
  			echo '
  USENET news host information:'
  			sed -n -e "/^Name:[ 	]*${arg}/,/^$/p" \
! 			`$look $lookopt$arg Index | awk '{print $2}'` /dev/null
  		done
  		exit 0
  	;;
@//E*O*F patches/
 
exit 0
-- 

John Quarterman, CS Dept., University of Texas, Austin, Texas 78712 USA
jsq@ut-sally.ARPA, jsq@ut-sally.UUCP, {ihnp4,seismo,ctvax}!ut-sally!jsq

lee@unmvax.UUCP (01/08/85)

 After receiving a letter from Mr. Quarterman it becomes obvious that
I opened my mouth without thinking again. My reply to his posting (upon
rereading it) obviously came across a bit smart-alecky. I did not intend
it as such, so I apologize.
 So, to restate my argument, with a little more thought and explanation
this time. chroot is not available to the normal user. The small piece
of code I posted was intended to be used in place
of his similar (in function) one so that Joe User could
make use of his package. I disagree with his use of chroot because it
is unnecessary.
 If someone chooses to use my algorithm instead of his I suggest that
they get the fixed version posted by Jay Plett as mine was erroneous.

-- 
			--Lee (Ward)
			{ucbvax,convex,gatech,pur-ee}!unmvax!lee