Return-Path: bind-request@uunet.uu.net
Received: by cognition.pa.dec.com; id AA20768; Thu, 6 May 93 22:31:27 -0700
Received: by inet-gw-2.pa.dec.com; id AA08078; Thu, 6 May 93 22:30:39 -0700
Received: by rodan.UU.NET (5.61/UUNET-mail-drop)
	id AA10465; Fri, 7 May 93 01:22:48 -0400
Received: from relay1.UU.NET by rodan.UU.NET with SMTP 
	(5.61/UUNET-mail-drop) id AA10461; Fri, 7 May 93 01:22:41 -0400
Received: from inet-gw-1.pa.dec.com by relay1.UU.NET with SMTP 
	(5.61/UUNET-internet-primary) id AA26744; Fri, 7 May 93 01:22:16 -0400
Received: by inet-gw-1.pa.dec.com; id AA23315; Thu, 6 May 93 22:19:41 -0700
Received: from ucsd.edu (ucsd.edu [128.54.16.1]) by vangogh.CS.Berkeley.EDU (ALPHA-6.55/6.25) id WAA29603; Thu, 6 May 1993 22:17:58 -0700
Received: by ucsd.edu; id AA23528
	sendmail 5.67/UCSD-2.2-sun
	Thu, 6 May 93 22:18:06 -0700 for bind@vangogh.CS.Berkeley.EDU
Date: Thu, 6 May 93 22:18:06 -0700
From: brian@UCSD.EDU (Brian Kantor)
Message-Id: <9305070518.AA23528@ucsd.edu>
To: bind@vangogh.CS.Berkeley.EDU, sra@epilogue.com
Subject: Re:  wish list

The AMPR.ORG domain is maintained by a mail robot which updates the zone
files through a simple unique-key database.  Maintenance of the entries
is split among more than 150 "coordinators" in more than 140 regions of
the world (more than 50 countries), with more than 15,000 entries in the
zone file.

It's simple stupid code, and people futz it up occasionally, but it works.
Sure, I have to go through the database every few weeks and clean out
the stupidities, but without the robot, I'd never have the time to maintain
it by hand!

These tools are included below primarily as inspiration; I'd hate to inflict
this Joe-code (I hacked it up in one weekend) on anyone who would run it as is.
	- Brian

::::::::::::::
/usr/ham/Makefile
::::::::::::::
all: ham.org hamhosts hamaddr ham.serial

ham.data: ham.pag dbtofile
	dbtofile ham | sort -u > ham.data
	chmod 664 ham.data
	/usr/etc/chown nobody.ham ham.data

ham.org:	ham.head ham.rev.head ham.data ham.serial
	cat ham.head ham.data > ham.org
	cat ham.rev.head > ham.org.rev
	fgrep '44.' ham.data | awk -f rev.awk >> ham.org.rev
	cp ham.org /usr/spool/ftp/hamradio/ham.org
	cp ham.org.rev /usr/spool/ftp/hamradio/ham.org.rev
	chmod 444 /usr/spool/ftp/hamradio/ham.org
	chmod 444 /usr/spool/ftp/hamradio/ham.org.rev
	/usr/etc/chown nobody.ham /usr/spool/ftp/hamradio/ham.org
	/usr/etc/chown nobody.ham /usr/spool/ftp/hamradio/ham.org.rev

hamhosts: ham.data
	awk -f hosts.awk < ham.data > hamhosts
	sort -nt. +1 -2 +2 -3 +3 -4 hamhosts -o hamhosts
	cp hamhosts /usr/spool/ftp/hamradio/hamhosts
	chmod 644 /usr/spool/ftp/hamradio/hamhosts
	/usr/etc/chown nobody.ham /usr/spool/ftp/hamradio/hamhosts

ham.serial:	ham.data serial newserial
	serial > ham.serial
	newserial

serial:	serial.c
	cc serial.c -O -o serial
::::::::::::::
/usr/ham/hosts.awk
::::::::::::::
/^#/		{print ""; print $0; h = "AaBbCc";next}

/IN	A/	{h = $1; 
			printf("\n%s\t%s",$4,$1)
			next}

$3 == "CNAME" && $4 == h	{printf " %s",$1}

END	{printf "\n"}
::::::::::::::
/usr/ham/rev.awk
::::::::::::::
/IN	A	44/	{ 
split($1, h, " "); 

split($4, a, ".");
if (a[1] == "" || a[2] == "" || a[3] == "")
	next;

if ( last4 != $4 ) {
	printf "%s.%s.%s\tIN\tPTR\t%s.ampr.org.\n", a[4],a[3],a[2],h[1]
	last4 = $4
	}
}
::::::::::::::
/usr/ham/hamaddr.c
::::::::::::::
#include <stdio.h>
#include <ndbm.h>
#include <strings.h>
#include <ctype.h>
#include <sys/file.h>

char buf[BUFSIZ];
char dat[6][128];
char from[BUFSIZ];
char keybuf[256];
char valbuf[256];

FILE *mailer;

#define sendmail "/usr/lib/sendmail -oi -t"
#define DB	"/usr/ham/ham"

DBM *db;
datum key, val;

main()
{
int nf;
int lc = 0;
int i;
char *c;
int hdr = 0;

mailer = popen(sendmail, "w");
if (mailer == NULL)
	{
	perror(sendmail);
	exit(-1);
	}

db = dbm_open(DB, O_RDWR, 0666);
if (db == NULL)
	{
	perror(DB);
	exit(1);
	}

while(fgets(buf, sizeof buf, stdin))
	{
	if ( (c = index(buf,'\n')) != NULL)
		*c = 0;
	
	if (strlen(buf) < 1)
		{
		hdr++;
		continue;
		}
	
	if (hdr == 0  && !strncmp(buf, "From:", 5))
		{
		fprintf(mailer, "From: ham-request@ucsd.edu\n");
		fprintf(mailer, "To: %s\n", &buf[5]);
		printf("------->To: %s\n", &buf[6]);
		fprintf(mailer, "Subject: address update rec'd\n");
		fprintf(mailer,"\n\n--- begin ---\n");
		continue;
		}

	if (hdr == 0)
		continue;

	fprintf(mailer,"> %s\n", buf);

	if ( (c = index(buf,'#')) != NULL)
		*c = 0;
	if ( (c = index(buf,';')) != NULL)
		*c = 0;
	if ( (c = index(buf,'\r')) != NULL)
		*c = 0;
	c = buf;
	while (*c)
		{
		if (isupper(*c))
			*c = tolower(*c);
		c++;
		}

	nf = sscanf(buf, "%s %s %s %s %s",
		dat[1], dat[2], dat[3], dat[4], dat[5]);
	
	if (nf < 2)
		{
		fprintf(mailer,"---> ignored\n");
		continue;
		}

	if (dat[1][strlen(dat[1])-1] == '.')
		{
		fprintf(mailer,"---> error: trailing period in field 1\n");
		continue;
		}

	if (dat[2][strlen(dat[2])-1] == '.')
		{
		fprintf(mailer,"---> error: trailing period in field 2\n");
		continue;
		}
	
	if (!strncmp(dat[1],"44.",3))	/* must be host table fmt */
		{
		lc++;
		fprintf(mailer,"%d ---> ADD/CHANGE: %s\tIN\tA\t%s\n",
				lc, dat[2], dat[1]);
		sprintf(keybuf,"A-%s", dat[2]);
		key.dptr = keybuf;
		key.dsize = strlen(key.dptr) + 1;
		sprintf(valbuf, "%s\tIN\tA\t%s\n",
				dat[2], dat[1]);
		val.dptr = valbuf;
		val.dsize = strlen(val.dptr) + 1;
		dbm_store(db, key, val, DBM_REPLACE);
		continue;
		}
	
	if (nf == 4 && !strcmp(dat[2],"in") && !strcmp(dat[3],"a"))
		{
		lc++;
		sprintf(keybuf,"A-%s", dat[1]);
		key.dptr = keybuf;
		key.dsize = strlen(key.dptr) + 1;
		sprintf(valbuf, "%s\tIN\tA\t%s\n", 
				dat[1], dat[4]);
		val.dptr = valbuf;
		val.dsize = strlen(val.dptr) + 1;
		if (strcmp(dat[4], "delete"))
			{
			dbm_store(db, key, val, DBM_REPLACE);
			fprintf(mailer,"%d ---> ADD/CHANGE: %s\tIN\tA\t%s\n", 
				lc, dat[1], dat[4]);
			}
		else
			{
			dbm_delete(db,key);
			fprintf(mailer,"%d ---> DELETED: %s\tIN\tA\t%s\n", 
				lc, dat[1], dat[4]);
			}
		continue;
		}
	
	if (nf == 4 && !strcmp(dat[2],"in") && !strcmp(dat[3],"cname"))
		{
		lc++;
		fprintf(mailer,"%d:\t%s\tIN\tCNAME\t%s\n", 
				lc, dat[1], dat[4]);
		sprintf(keybuf,"C-%s", dat[1]);
		key.dptr = keybuf;
		key.dsize = strlen(key.dptr) + 1;
		sprintf(valbuf, "%s\tIN\tCNAME\t%s\n", 
				dat[1], dat[4]);
		val.dptr = valbuf;
		val.dsize = strlen(val.dptr) + 1;
		if (strcmp(dat[4], "delete"))
			{
			dbm_store(db, key, val, DBM_REPLACE);
			fprintf(mailer,"%d ---> ADD/CHANGE: %s\tIN\tA\t%s\n", 
				lc, dat[1], dat[4]);
			}
		else
			{
			dbm_delete(db,key);
			fprintf(mailer,"%d ---> DELETED: %s\tIN\tA\t%s\n", 
				lc, dat[1], dat[4]);
			}
		continue;
		}
	
	if (nf == 5 && !strcmp(dat[2],"in") && !strcmp(dat[3],"mx")
	&& isdigit(dat[4][0]))
		{
		lc++;
		fprintf(mailer,"%d:\t%s\tIN\tMX %s\t%s\n", 
				lc, dat[1], dat[4], dat[5]);
		sprintf(keybuf,"M%s-%s", dat[4], dat[1]);
		key.dptr = keybuf;
		key.dsize = strlen(key.dptr) + 1;
		sprintf(valbuf, "%s\tIN\tMX %s\t%s\n", 
				dat[1], dat[4], dat[5]);
		val.dptr = valbuf;
		val.dsize = strlen(val.dptr) + 1;
		if (strcmp(dat[5], "delete"))
			{
			dbm_store(db, key, val, DBM_REPLACE);
			fprintf(mailer,"%d ---> ADD/CHANGE: %s\tIN\tMX %s\t%s\n", 
				lc, dat[1], dat[4], dat[5]);
			}
		else
			{
			dbm_delete(db,key);
			fprintf(mailer,"%d ---> DELETED: %s\tIN\tMX %s\t%s\n", 
				lc, dat[1], dat[4], dat[5]);
			}
		continue;
		}
	
	fprintf(mailer,"---> skipped: record format error\n");
	}

fprintf(mailer,"--- end ---\n");
fflush(mailer);
pclose(mailer);
dbm_close(db);
exit(0);
}
::::::::::::::
/usr/ham/dbtofile.c
::::::::::::::
/*
 * dumps DBM database contents to stdout
 */

#include <stdio.h>
#include <ndbm.h>
#include <sys/file.h>

char buf[BUFSIZ];

DBM *db;
datum key, val;

main(argc,argv)
int argc;
char **argv;
	{
	if (argc != 2)
		{
		fprintf(stderr,"Usage: dbtofile db \n");
		exit(1);
		}

	if ((db = dbm_open(argv[1], O_RDONLY, 0)) < 0)
		{
		perror(argv[1]);
		exit(1);
		}

	for (key = dbm_firstkey(db); key.dptr != NULL;
				key = dbm_nextkey(db))
		{
		val = dbm_fetch(db, key);
		puts(val.dptr);
		}
	}
::::::::::::::
/usr/ham/serial.c
::::::::::::::
#include <stdio.h>
#include <sys/time.h>

main()
	{
	struct tm *tm;
	struct timeval tv;
	struct timezone tz;

	gettimeofday(&tv,&tz);

	tm = gmtime(&tv.tv_sec);

	printf("\t\t\t\t%02d%02d%02d%02d\t; Serial\n",
		tm->tm_year, (tm->tm_mon + 1), tm->tm_mday, tm->tm_hour);
	exit(0);
	}
::::::::::::::
/usr/ham/newserial
::::::::::::::
#!/bin/sh
for f in \
	ham.head \
	ham.rev.head \
		; do
ex $f << EOF > /dev/null
/Serial/
d
-
r ham.serial
w
q
EOF
echo $f 'updated' ;
done ;
exit 0
