[alt.sources] uucp map browser in perl?

vixie@wrl.dec.com (Paul Vixie) (11/06/90)

# Before someone goes and reinvents another wheel...  does anyone have
# any perl scripts for searching or browsing the Uucp maps?
# -- 
# Richard Foulk		richard@pegasus.com

Here's what we use here.  Complete but not documented.  Includes the
"unpackmaps" unpacker, the IDA "dbm" command, the smail "lcasep" command,
and probably other junk from other sources.  Only the index-builder and
browser are currently mine.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  INFO.costs Makefile README.unpackmaps dbm.c get.pl
#   lcasep.c list.pl mailpath.sh makefile.libd.src mkall.pl
#   mkmap.pl.src mkone.pl unpackmaps.sh uuhost.sh uupath.sh uupaths.sh
#   wrl-uumap.pl.src
# Wrapped by vixie@jove.pa.dec.com on Tue Nov  6 00:09:01 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'INFO.costs' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'INFO.costs'\"
else
echo shar: Extracting \"'INFO.costs'\" \(401 characters\)
sed "s/^X//" >'INFO.costs' <<'END_OF_FILE'
X          LOCAL       25   (local-area network connection)
X          DEDICATED   95   (high speed dedicated link)
X          DIRECT     200   (toll-free call)
X          DEMAND     300   (long-distance call)
X          HOURLY     500   (hourly poll)
X          EVENING   1800   (time restricted call)
X          DAILY     5000   (daily poll, also called POLLED)
X          WEEKLY   30000   (irregular poll)
END_OF_FILE
if test 401 -ne `wc -c <'INFO.costs'`; then
    echo shar: \"'INFO.costs'\" unpacked with wrong size!
fi
# end of 'INFO.costs'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(3058 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile for uucp map maintainance utilities
X# originally from  @(#)Makefile	1.1 6/15/87 jbuck@epimass.epi.com
X#
X# vixie@decwrl.dec.com: BSD-ified, added other utilities from uucpmap package
X#	21Sep88
X
NEWSUSR		=news
LIBD		=/wrl/gen/lib/uumap
MAPD		=$(LIBD)/maps
BIND		=/usr/local/bin
GENBIND		=/wrl/gen/bin
MANL		=1
MAND		=/usr/local/man/man$(MANL)
PERLLIB		=/usr/local/lib/perl
NEWSSPOOL	=/usr/spool/news
BATCH		=/usr/spool/news/out.special/maps
X
X# pick the empty one if your ndbm routines are in your /lib/libc.a
X#NDBM=
X# pick this one if you have a libndbm.a file in /usr/lib or /usr/local/lib
NDBM= -lndbm
X
CFLAGS		= -O
INFO		= INFO.costs
BIN_TARGETS	= lcasep dbm
OTHER_TARGETS	= uuhost uupath uupaths makefile.libd mailpath unpackmaps \
X			get list mkall mkone wrl-uumap.pl mkmap.pl
TARGETS		= $(BIN_TARGETS) $(OTHER_TARGETS)
X
all:		$(TARGETS)
X
clean:;		rm -f $(TARGETS) *.o *.BAK *.CKP *~ .emacs*
X
lcasep:		lcasep.o
X		cc -o lcasep lcasep.o
X
dbm:		dbm.o
X		cc -o dbm dbm.o $(NDBM)
X
uupath:		uupath.sh Makefile
X		sed -e 's?>BIND<?$(BIND)?g' -e 's?>LIBD<?$(LIBD)?g' $@.sh > $@
X		chmod +x uupath
X
uupaths:	uupaths.sh Makefile
X		sed -e 's?>LIBD<?$(LIBD)?g' $@.sh > $@
X		chmod +x uupaths
X
mailpath:	mailpath.sh Makefile
X		sed	<$@.sh >$@ \
X			-e 's?>LIBD<?$(LIBD)?g' \
X			-e 's?>BIND<?$(BIND)?g'
X		chmod +x mailpath
X
unpackmaps:	unpackmaps.sh Makefile
X		sed	<$@.sh >$@ \
X			-e 's?>BATCH<?$(BATCH)?g' \
X			-e 's?>NEWSSPOOL<?$(NEWSSPOOL)?g' \
X			-e 's?>MAPDIR<?$(MAPD)?g'
X		chmod +x unpackmaps
X
uuhost:		uuhost.sh Makefile
X		sed	<$@.sh >$@ \
X			-e 's?>LIBD<?$(LIBD)?g'
X		chmod +x uuhost
X
get:		get.pl
X		cp get.pl get
X		chmod +x get
X
list:		list.pl
X		cp list.pl list
X		chmod +x list
X
mkall:		mkall.pl
X		cp mkall.pl mkall
X		chmod +x mkall
X
mkone:		mkone.pl
X		cp mkone.pl mkone
X		chmod +x mkone
X
mkmap.pl:	mkmap.pl.src
X		cp mkmap.pl.src mkmap.pl
X
makefile.libd:	makefile.libd.src Makefile
X		sed	<$@.src >$@ \
X			-e 's?>MAPD<?$(MAPD)?g' \
X			-e 's?>LIBD<?$(LIBD)?g' \
X			-e 's?>BIND<?$(BIND)?g' \
X			-e 's?>MAPS<?$(MAPS)?g'
X
wrl-uumap.pl:	wrl-uumap.pl.src Makefile
X		sed	<$@.src >$@ \
X			-e 's?>CODE<?$(LIBD)?g' \
X			-e 's?>DATA<?$(LIBD)?g' \
X			-e 's?>MAPS<?$(MAPD)?g'
X
install:	$(TARGETS) $(INFO)
X		test -d $(LIBD) ||	mkdir $(LIBD); \
X					/etc/chown $(NEWSUSR) $(LIBD); \
X					/bin/chgrp $(NEWSUSR) $(LIBD); \
X					/bin/chmod 775 $(LIBD)
X		test -d $(BIND) ||	mkdir $(BIND)
X		-test -d $(MAND) ||	mkdir $(MAND)
X		install -c -s -m 555 lcasep   $(BIND)/
X		install -c -s -m 555 dbm      $(BIND)/
X		install -c    -m 555 uuhost   $(GENBIND)/
X		install -c    -m 555 uupath   $(GENBIND)/
X		install -c    -m 555 uupaths  $(GENBIND)/
X		install -c    -m 555 mailpath $(GENBIND)/
X		install -c    -m 444 wrl-uumap.pl $(PERLLIB)/
X		install -c    -m 444 mkmap.pl $(LIBD)/
X		install -c    -m 555 get      $(LIBD)/
X		install -c    -m 555 list     $(LIBD)/
X		install -c    -m 555 mkall    $(LIBD)/
X		install -c    -m 555 mkone    $(LIBD)/
X		install -c    -m 555 unpackmaps $(LIBD)/
X		install -c    -m 444 makefile.libd $(LIBD)/makefile
X		install -c    -m 444 INFO.costs $(LIBD)/
END_OF_FILE
if test 3058 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README.unpackmaps' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README.unpackmaps'\"
else
echo shar: Extracting \"'README.unpackmaps'\" \(7475 characters\)
sed "s/^X//" >'README.unpackmaps' <<'END_OF_FILE'
X			UNPACKMAPS V3.0
X			  May 14 1990
X			  Chris Lewis
X
X    This README, unpackmaps and uuwhere are Copyright 1990 Chris Lewis,
X    All Rights Reserved.
X
X    You can do anything you want with it, provided that this copyright
X    notice remains intact, you don't claim you wrote it yourself, and you 
X    don't make money selling it directly.  You may redistribute this as
X    you wish, but if you modify it, you should clearly indicate in this
X    README file that it has been modified, by whom, and describe what
X    has been changed.  Reasonable copying charges are okay.
X
X    Though I have taken pains to ensure that this program is reasonably 
X    reliable and secure, I cannot make any warrantee as to the reliability 
X    or security of this software when used on any computer.  It is up to
X    the user of this software to determine its suitability for their
X    purposes and take responsibility for its operation.
X
This is source for a simple, *secure*, map unpacking facility.
X
It is much simpler than uuhosts, has roughly the same functionality,
is easier to install, probably faster and more efficient (at least
the versions I've seen w.r.t. compression), and is considerably less 
vulnerable to trojan maps than most map unpackers that other people use.
X(It has fewer vulnerabilities than uuhosts)
X
The intent is that any UNIX/XENIX/BSD system that can run news will
be able to run this too, so I'm attempting to keep to greatest-common-
denominator except for pathalias and things that I implement myself.
X
This release includes:
X
X	- map unpacking
X	- pathalias operation plus hooks for path customization.
X	- a mechanism for viewing map entries for arbitrary sites.
X	  ("uuwhere")
X	- automatic map article deletion if desired.
X
This had been posted to comp.sources.misc about a year ago.  The
prime differences here are that compress is run as a pipeline as stdin to
pathalias, so you don't need to modify pathalias anymore, and the
new "uuwhere" tool.  There is still no makefile because it wouldn't
do anything useful.
X
Regarding security: as many may remember, there's been a fair bit of
discussion on security of map unpacking on the net.  Rather than play
around with trying to make a secure *true* unshar, which probably noone would
trust because it would be so big, I simply made a few simplifying assumptions
about the map format and use an awk script to unpack a map article into
a map file.  It checks for and refuses to unpack articles which have
slashes in their names.  I sent off some mail to Mel asking whether the
assumptions I've made about map format are true, but never got any
response.  I believe that this is *pretty* secure, in that it doesn't
have to be run as root, doesn't use the Bourne shell for unpacking, and 
is careful about the file names it creates.  Please let me know if there 
are any holes I didn't think of.
X
General operation:
X	- your news is modified to batch incoming map article file names
X	  to a specific batch file (analogous to normal news batching).  
X	  C-news users take note: you may have to utter magic incantations 
X	  (hint "classes" in C-news Alpha) to get sendbatches to avoid 
X	  trying to uux these...  Another way is to use an explicit batch 
X	  file name in the sys file that isn't under the usual "out.going"
X	  directories and point unpackmaps at it.
X	- unpackmaps wakes up, usually once per day, and extracts the
X	  maps specified (if any) in the batch file into the map directory.
X	  Maps are extracted using a secure awk script without resort
X	  to setuid root or other wierdnesses.  If you want the uuwhere
X	  facility, unpackmaps will extract site->map file correspondences.
X	- If any maps were extracted, pathalias is fired off, and the 
X	  resultant file put in the place specified.
X	- If you've specified uuwhere, the where database will be regenerated.
X	- if anything was done, unpackmaps sends you mail telling you
X	  what happened.
X
Installation:
X	- If you want to compress the stored map files, set the COMPRESS
X	  variable to point your compress program.  You should be using
X	  compress versions 3 or 4.  A copy will have come with your
X	  news software.
X
X	- I STRONGLY recommend that you build a special version of compress
X	  with 12 bit compression instead of 16 for this.  When this
X	  is done, compress is considerably smaller (eg: bss of 32K instead
X	  of 400K+).  The reason for this is obvious - pathalias is enormous
X	  when it's running, and so is a 16 bit compress.  God help you if
X	  it starts to swap.
X
X	  Advantages:
X		- the whole thing runs considerably faster
X		- much less swap/paging
X		- on our machine, 16 bit compress practically hangs
X		  everyone else when run at the same time as pathalias.
X
X	  Disadvantages:
X		- the map directory is 10% (really!  only 10%!) bigger.
X
X	  What I did was the following:
X		- go to the source directory for compress
X		- remove the binary if it is there.
X		- say:
X			make compress CFLAGS=-DUSERMEM=0
X		- rename this to something like /usr/bin/compress12
X		- make sure that uuwhere and unpackmaps shell scripts
X		  have the same name.  Eg: /usr/bin/compress12
X
X	- edit unpackmaps to set the variables at the beginning of
X	  the shell script.  Note especially the batch file name
X	  (see below)
X	- make the directory for the map files, owned by news.
X	- put unpackmaps in a suitable place.  Eg: /usr/lib/news
X	- put uuwhere in a suitable place.  Eg: /usr/local/bin.
X	- unpackmaps should be run from the userid that owns and runs news.
X	- su to the news userid, and run:
X		unpackmaps -i
X	  This will build the initial path file.
X	- insert into your crontab something like:
X	    30 3 * * * /bin/su news -c "<path to unpackmaps>/unpackmaps > /dev/null"
X	- insert into your news sys file something like:
X
X	    (C-news)
X
X	    maps:comp.mail.maps/all:f:/usr/spool/news/out.special/maps
X
X	    (B-news)
X
X	    maps:world,comp.mail.maps:F:/usr/spool/batch/maps
X
X	- copy uuwhere to an accessible bin directory after modifying
X	  the configuration section at the beginning.
X    
uuwhere "sitename" will give you the map name and line numbers where
the site is defined (with #N comments).  Adding a -v option will
invoke compress (if necessary) and show you the map entry itself.
The uuwhere mechanism *only* works using the "#N" entries, and will
not search for macro reassignments and other namings.  One other drawback
is that uuwhere won't display whole map files directly, but that was
never particularly useful anyways.
X
unpackmaps -i: will extract all map articles into the map spool area - useful
for the first time you use it.
X
unpackmaps -p: runs pathalias even if no map articles were extracted.
X
In order to push the paths file into /usr/lib/uucp, I created a file called
paths in /usr/lib/uucp, with 644 permissions, owned by the userid that runs
unpackmaps.
X
The package will send mail to who you specify indicating which maps were
unpacked, and any error returns from pathalias.
X
The uuwhere database is built from the maps as they are unpacked.  After
installation, it may take a while for the where database to be complete.
X(same as for path files themselves too).  I have implemented a binary
search routine to make uuwhere go faster, but frankly, the sed's fast
enough on all but the slowest machine.
X
Let me know of any changes you needed to make to get this to work.
I'm also open to suggestions for new features....
X----------
Chris Lewis, Markham, Ontario, Canada
X{uunet!attcan,utgpu,yunexus,utzoo}!lsuc!{ecicrl|eci386}!clewis
END_OF_FILE
if test 7475 -ne `wc -c <'README.unpackmaps'`; then
    echo shar: \"'README.unpackmaps'\" unpacked with wrong size!
fi
# end of 'README.unpackmaps'
fi
if test -f 'dbm.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dbm.c'\"
else
echo shar: Extracting \"'dbm.c'\" \(10914 characters\)
sed "s/^X//" >'dbm.c' <<'END_OF_FILE'
X/*
X**  DBM -- General dbm management tool.
X**  Copyright (c) 1987 Lennart Lovstrand
X**  CIS Dept, Univ of Linkoping, Sweden
X**
X**  Use it, abuse it, but don't sell it.
X*/
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/file.h>
X#ifdef MDBM
X# include "mdbm_compat.h"
X#else MDBM
X# include <ndbm.h>
X# define DBMFILE DBM
X#endif MDBM
X
X#ifndef lint
static char	SccsId[] = "@(#)dbm.c 2.0 (lel@ida.liu.se) 4/20/87";
X#endif !lint
X
X#define TRUE 1
X#define FALSE 0
typedef int bool;
X
X#define	SAMECASE	0
X#define LOWERCASE	1
X#define UPPERCASE	2
X
X#define COMMENTCHAR	'#'
X
X#define streq(s, t)	(strcmp(s, t) == 0)
X#define MAKEDATUM(d, s)	{(d).dptr = s; (d).dsize = strlen(s) + 1;}
X
void do_clear(), do_delete(), do_dump(), do_fetch(), do_load(), do_make(),
X    do_parse(), do_store();
X
struct comtab {
X    char *c_name;
X    void (*c_func)();
X} CommandTable[] = {
X    {"clear",	do_clear},
X    {"delete",	do_delete},
X    {"dump",	do_dump},
X    {"fetch",	do_fetch},
X    {"load",	do_load},
X    {"make",	do_make},
X    {"parse",	do_parse},
X    {"store",	do_store}
X};
X    
X/* global arguments */
int	Argc;
char	**Argv;
X
X/* options */
int	Appending = FALSE;
int	Casing = SAMECASE;
bool	Debug = FALSE;
char	*Outfile = NULL;
int	Mode = 0644;
char	*Progname;
bool	Senteniel = FALSE;
int	Storeflag = DBM_INSERT;
bool	Storewarn = TRUE;
X
X/* Dbm globals */
DBMFILE	*Dbm;
char	*Dbmfile = NULL;
int	Dbmaccess;
datum	key, val;
X
main(argc, argv)
X     int argc;
X     char **argv;
X{
X    extern int optind;
X    extern char *optarg;
X    char *scantoken();
X    struct comtab *cmd;
X    int c;
X
X    Argc = argc;
X    Argv = argv;
X
X    Progname = Argv[0];
X
X    while ((c = getopt(Argc, Argv, "ADILRSUd:m:o:")) != EOF)
X	switch (c) {
X	  case 'A':
X	    Appending = TRUE;
X	    break;
X	  case 'D':
X	    Debug = TRUE;
X	    break;
X	  case 'I':
X	    Storeflag = DBM_INSERT;
X	    Storewarn = FALSE;
X	    break;
X	  case 'L':
X	    Casing = LOWERCASE;
X	    break;
X	  case 'R':
X	    Storeflag = DBM_REPLACE;
X	    break;
X	  case 'S':
X	    Senteniel = TRUE;
X	    break;
X	  case 'U':
X	    Casing = UPPERCASE;
X	    break;
X	  case 'd':
X	    Dbmfile = optarg;
X	    break;
X	  case 'm':
X	    if (optarg[0] == '0')
X		(void) sscanf(optarg, "%o", &Mode);
X	    else {
X		(void) sscanf(optarg, "%d", &Mode);
X		if (Mode == 0) {
X		    (void) fprintf(stderr, "%s: non-numeric mode: %s\n",
X				   Progname, optarg);
X		    exit(1);
X		}
X	    }
X	    break;
X	  case 'o':
X	    Outfile = optarg;
X	    break;
X	  default:
X	    (void) fprintf(stderr,
X			   "usage: %s [-ADILNRSU] [-d dbm_file] [-m mode] %s", 
X			   Progname, "[-o output_file] command [args]\n");
X	    exit(1);
X	}
X
X    Argc -= optind;
X    Argv += optind;
X
X    if (Argc > 0) {
X	for (cmd = CommandTable; cmd < &CommandTable[sizeof(CommandTable) /
X						     sizeof(*CommandTable)];
X	     cmd++)
X	    if (streq(*Argv, cmd->c_name)) {
X		(*cmd->c_func)();
X		exit(0);
X	    }
X	(void) fprintf(stderr, "%s: unknown dbm command %s", Progname, *Argv);
X    } else
X	(void) fprintf(stderr, "%s: missing dbm command", Progname);
X    (void) fprintf(stderr, ", use one of the following:\n");
X    for (cmd = CommandTable; cmd < &CommandTable[sizeof(CommandTable) /
X						 sizeof(*CommandTable)]; cmd++)
X	(void) fprintf(stderr, "%s%s", cmd == CommandTable ? "" : "\t",
X		       cmd->c_name);
X    (void) fprintf(stderr, "\n");
X    exit(3);
X}
X
opendbm(access)
X     int access;
X{
X    if (Dbmfile == NULL) {
X	if (Argc > 1) {
X	    /* use last argument */
X	    Dbmfile = Argv[Argc-1];
X	    Argc--;
X	} else {
X	    (void) fprintf(stderr, "%s: dbm file not specified\n", Progname);
X	    exit(3);
X	}
X    }
X    Dbm = dbm_open(Dbmfile, access, Mode);
X    if (Dbm == NULL) {
X	perror(Dbmfile);
X	exit(4);
X    }
X    Dbmaccess = access;
X}
X
closedbm()
X{
X    if ((Dbmaccess & O_RDONLY) == 0 && Senteniel) {
X	MAKEDATUM(key, "@@@");
X	if (dbm_store(Dbm, key, key, DBM_REPLACE) != NULL) {
X	    (void) fprintf(stderr, "%s: could not store senteniel \"@@@\"\n",
X			   Progname);
X	    perror(Progname);
X	    exit(5);
X	}
X    }
X	
X    dbm_close(Dbm);
X}
X
XFILE *
openfile(filename, access)
X     char *filename;
X     char *access;
X{
X    FILE *f;
X
X    if (streq(filename, "-"))
X	if (streq(access, "r"))
X	    return stdin;
X	else
X	    return stdout;
X    else {
X	f = fopen(filename, access);
X	if (f == NULL) {
X	    perror(filename);
X	    exit(4);
X	}
X	return f;
X    }
X}
X
void
closefile(f)
X     FILE *f;
X{
X    if (f != stdin && f != stdout)
X	(void) fclose(f);
X}
X/*
X**	DO_CLEAR -- Clear out database leaving it emtpy.
X*/
X
void
do_clear()
X{
X    if (Dbmfile != NULL) {
X	opendbm(O_RDWR | O_CREAT | O_TRUNC);
X	closedbm();
X    }
X    while (Argc > 1) {
X	opendbm(O_RDWR | O_CREAT | O_TRUNC);
X	closedbm();
X    }
X}
X
X   
X/*
X**	DO_DELETE -- Delete individual entries from the database.
X*/
X
void
do_delete()
X{
X    opendbm(O_RDWR | O_CREAT);
X
X    for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
X	casify(*Argv, Casing);
X	MAKEDATUM(key, *Argv);
X	if (dbm_delete(Dbm, key) != NULL) {
X	    perror(*Argv);
X	    exit(5);
X	}
X    }
X
X    closedbm();
X}
X
X/*
X**	DO_DUMP -- List all entries in the database.
X*/
X 
void
do_dump()
X{
X    FILE *output;
X    
X    opendbm(O_RDONLY);
X
X    if (Outfile == NULL)
X	output = stdout;
X    else
X	output = openfile(Outfile, "w");
X
X#ifdef MDBM
X    for (key = dbm_firstkey(Dbm); key.dptr != NULL; key = dbm_nextkey(Dbm, key)) {
X#else MDBM
X    for (key = dbm_firstkey(Dbm); key.dptr != NULL; key = dbm_nextkey(Dbm)) {
X#endif MDBM
X	val = dbm_fetch(Dbm, key);
X	if (val.dptr == NULL)
X	    perror(key.dptr);
X	else
X	    (void) fprintf(output, "%s\t%s\n", key.dptr, val.dptr);
X    }
X}
X/*
X**	DO_FETCH -- Lookup individual keys in the database.
X*/
X 
void
do_fetch()
X{
X    opendbm(O_RDONLY);
X
X    for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
X	casify(*Argv, Casing);
X	MAKEDATUM(key, *Argv);
X	val = dbm_fetch(Dbm, key);
X	if (val.dptr == NULL)
X	    (void) printf("%s\t[NOT FOUND]\n", *Argv);
X	else
X	    (void) printf("%s\t%s\n", *Argv, val.dptr);
X    }
X
X    closedbm();
X}
X
X/*
X**	DO_STORE -- Insert individual entries into the database.
X*/
X
void
do_store()
X{
X    /* barf if # of args - 1 is even and no dbm file has been specified */
X    if (Argc & 1 == 1 && Dbmfile == NULL) {
X	(void) fprintf(stderr, "%s: no dbm file specified\n", Progname);
X	exit(3);
X    }
X
X    opendbm(O_RDWR | O_CREAT);
X
X    for (Argc--, Argv++; Argc > 1; Argc -= 2, Argv += 2) {
X	casify(Argv[0], Casing);
X	MAKEDATUM(key, Argv[0]);
X	MAKEDATUM(val, Argv[1]);
X	if (dbm_store(Dbm, key, val, Storeflag) != NULL) {
X	    extern int errno;
X
X	    if (errno != 0) {
X		perror(Argv[0]);
X		exit(5);
X	    } else if (Storewarn)
X		(void) fprintf(stderr,
X			       "%s: duplicate key \"%s\" => \"%s\" ignored\n",
X			       Progname, Argv[0], Argv[1]);
X	}
X    }
X    if (Argc > 0)
X	(void) fprintf(stderr, "%s: no value for last key \"%s\"--ignored\n",
X		       Progname, Argv[0]);
X
X    closedbm();
X}
X
X/*
X**	DO_PARSE -- Parse a textual database file and produce key-value
X**		pairs separated by a tab (suitable for input to the ``load''
X**		function).
X*/
X
void
do_parse()
X{
X    FILE *input, *output;
X    
X    if (Outfile == NULL)
X	output = stdout;
X    else
X	output = openfile(Outfile, "w");
X
X    if (Argc == 1)
X	parsefile(stdin, output);
X    else
X	for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
X	    input = openfile(*Argv, "r");
X	    parsefile(input, output);
X	    closefile(input);
X	}
X}
X
X/*
X**	DO_MAKE -- Parse the textual input and load the result into
X**		the database.
X*/
X
void
do_make()
X{
X    FILE *input, *pipin, *pipout;
X    int pipes[2];
X
X    opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC));
X
X    if (pipe(pipes) != NULL) {
X	perror("pipe");
X	exit(9);
X    }
X    pipin = fdopen(pipes[0], "r");
X    pipout = fdopen(pipes[1], "w");
X
X    if (fork() == 0) {
X	/* child process */
X	(void) fclose(pipout);
X
X	loadfile(pipin);
X    } else {
X	/* parent process */
X	(void) fclose(pipin);
X
X	if (Argc == 1)
X	    parsefile(stdin, pipout);
X	else
X	    for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
X		input = openfile(*Argv, "r");
X		parsefile(input, pipout);
X		closefile(input);
X	    }
X    }
X    closedbm();
X}
X
X/*
X**	DO_LOAD -- Load the dbm database from a text file.  The input should
X**		be key-value pairs separated by a tab, each on a single line.
X*/
X
void
do_load()
X{
X    FILE *input;
X
X    opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC));
X
X    if (Argc == 1)
X	loadfile(stdin);
X    else
X	for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
X	    input = openfile(*Argv, "r");
X	    loadfile(input);
X	    closefile(input);
X	}
X    closedbm();
X}    
X
X/*
X**	PARSEFILE, LOADFILE
X*/ 
X
parsefile(input, output)
X     FILE *input, *output;
X{
X    extern char *index();
X    char buf[BUFSIZ], *key, *val = NULL;
X    register char *p;
X
X    while (fgets(buf, sizeof(buf), input) != NULL) {
X	if (buf[0] == COMMENTCHAR || buf[0] == '\n' || buf[0] == '\0')
X	    continue;
X	if (!isspace(buf[0])) {
X	    /* extract value */
X	    p = scantoken(buf);
X	    if (val != NULL)
X		free(val);
X	    val = (char *) malloc(p - buf + 1);
X	    (void) strncpy(val, buf, p - buf);
X	    val[p - buf] = '\0';
X	}
X	casify(buf, Casing);
X	for (p = buf; *p != '\0';) {
X	    while (*p != '\0' && isspace(*p)) p++;
X	    if (*p == '\0' || *p == COMMENTCHAR)
X		break;
X	    key = p;
X	    p = scantoken(p);
X	    if (*p == COMMENTCHAR)
X		*p = '\0';
X	    else if (*p != '\0')
X		*p++ = '\0';
X	    (void) fprintf(output, "%s\t%s\n", key, val);
X	}
X    }
X}
X
loadfile(input)
X     FILE *input;
X{
X    char buf[BUFSIZ];
X    register char *tab, *nl;
X    extern char *index();
X
X    while (fgets(buf, sizeof(buf), input) != NULL) {
X	nl = index(buf, '\n');
X	if (nl != NULL)
X	    *nl = '\0';
X
X	tab = index(buf, '\t');
X	if (tab == NULL) {
X	    (void) fprintf(stderr, "%s: missing tab in \"%s\"--ignored\n",
X			   Progname, buf);
X	    continue;
X	}
X	*tab++ = '\0';
X	casify(buf, Casing);
X	MAKEDATUM(key, buf);
X	MAKEDATUM(val, tab);
X	if (dbm_store(Dbm, key, val, Storeflag) != NULL && Storewarn) {
X	    extern int errno;
X
X	    if (errno != 0) {
X		perror(buf);
X		exit(5);
X	    } else if (Storewarn)
X		(void) fprintf(stderr,
X			       "%s: duplicate key \"%s\" => \"%s\" ignored\n",
X			       Progname, buf, tab);
X	}
X    }
X}
X
char *
scantoken(p)
X     register char *p;
X{
X  register bool quotedchar = FALSE, insidestring = FALSE, insideroute = FALSE;
X
X  /* hidious address scanner */
X  while (*p != '\0' && (quotedchar || insidestring || insideroute || 
X			(*p != COMMENTCHAR && !isspace(*p)))) {
X    /* special quote character handling */
X    if (quotedchar)
X      quotedchar = FALSE;
X    else {
X      quotedchar = (*p == '\\');
X      if (!insidestring)
X	if (*p == '<')
X	  insideroute = TRUE;
X	else if (*p == '>')
X	  insideroute = FALSE;
X      if (*p == '"')
X	insidestring = !insidestring;
X    }
X    p++;
X  }
X
X  return p;
X}
X
casify(p, c)
X     register char *p;
X     int c;
X{
X    switch (c) {
X      case LOWERCASE:
X	for (; *p != '\0'; p++)
X	    if (isupper(*p))
X		*p = tolower(*p);
X	break;
X      case UPPERCASE:
X	for (; *p != '\0'; p++)
X	    if (islower(*p))
X		*p = toupper(*p);
X	break;
X    }
X}
END_OF_FILE
if test 10914 -ne `wc -c <'dbm.c'`; then
    echo shar: \"'dbm.c'\" unpacked with wrong size!
fi
# end of 'dbm.c'
fi
if test -f 'get.pl' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'get.pl'\"
else
echo shar: Extracting \"'get.pl'\" \(943 characters\)
sed "s/^X//" >'get.pl' <<'END_OF_FILE'
X#! /usr/local/bin/perl
X
do "wrl-uumap.pl" || die "can't do wrl-uumap.pl";
package main;
X
dbmopen(mapdb, "$uumap'data/mapdb", 0666) || die "can't open mapdb: $!";
X
chdir "$uumap'maps" || die "can't chdir: $!";
X
foreach $name (@ARGV) {
X
X	undef %trail;
X	while ($cname = $mapdb{$name,"alias"}) {
X		if ($trail{$cname}) {
X			print "alias loop for ${cname}\n";
X			last;
X		}
X		$trail{$name} = 1;
X		$name = $cname;
X	}
X
X	($map,$pos) = split('@', $mapdb{$name,"map"});
X	if ($map eq "") {
X		printf("%s: no map\n", $name);
X		next;
X	}
X
X	@aliases = split('@', $mapdb{$name,"aliases"});
X
X	printf("=== %s ===", $name);
X	if ($#aliases >= $[) {
X		printf(" (also: %s)", join(' ',@aliases));
X	}
X	printf("\n");
X
X	if (!open(map, $map)) {
X		warn "can't open $map: $!";
X		next;
X	}
X	seek(map, $pos, 0) || warn "can't seek to $pos in $map: $!";
X	$n = 0;
X	while (<map>) {
X		if (/^#[Nn]/) {
X			last if (++$n > 1);
X		}
X		print;
X	}
X	close(map);
X}
X
dbmclose(mapdb);
X
exit 0;
END_OF_FILE
if test 943 -ne `wc -c <'get.pl'`; then
    echo shar: \"'get.pl'\" unpacked with wrong size!
fi
# end of 'get.pl'
fi
if test -f 'lcasep.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lcasep.c'\"
else
echo shar: Extracting \"'lcasep.c'\" \(1163 characters\)
sed "s/^X//" >'lcasep.c' <<'END_OF_FILE'
X/*
X** convert the host name on a pathalias line to lower case
X*/
X
X#ifndef lint
static char 	*sccsid="@(#)lcasep.c	2.5 (smail) 9/15/87";
X#endif
X
X#include <stdio.h>
X#include <ctype.h>
X
X# define lower(c) 		( isupper(c) ? c-'A'+'a' : c )
X
void exit(), perror();
X
main(argc, argv)
int argc;
char *argv[];
X{
X	FILE *ifp, *ofp;
X	char buf[BUFSIZ];
X	register char *p;
X	int c;
X
X	extern int optind;
X	extern char *optarg;
X
X	ifp = stdin;
X	ofp = stdout;
X
X	while((c = getopt(argc, argv, "f:o:")) != EOF) {
X		switch(c) {
X		case 'f':
X			if((ifp = fopen(optarg, "r")) == NULL) {
X				(void) fprintf(stderr, "%s: can't open %s: ",
X					argv[0], optarg);
X				perror("");
X				exit(1);
X			}
X			break;
X		case 'o':
X			if((ofp = fopen(optarg, "w")) == NULL) {
X				(void) fprintf(stderr, "%s: can't open %s: ",
X					argv[0], optarg);
X				perror("");
X				exit(1);
X			}
X			break;
X		default:
X			(void) fprintf(stderr,
X				"usage: %s [-f file] [-o outfile]\n", argv[0]);
X			exit(1);
X			/* NOTREACHED */
X			break;
X		}
X	}
X
X	while(fgets(buf, sizeof(buf), ifp) != NULL) {
X		for(p = buf; *p != '\t' && *p != '\0' ; p++) {
X			(void) fputc(lower(*p), ofp);
X		}
X		(void) fputs(p, ofp);
X	}
X	return(0);
X}
END_OF_FILE
if test 1163 -ne `wc -c <'lcasep.c'`; then
    echo shar: \"'lcasep.c'\" unpacked with wrong size!
fi
# end of 'lcasep.c'
fi
if test -f 'list.pl' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'list.pl'\"
else
echo shar: Extracting \"'list.pl'\" \(282 characters\)
sed "s/^X//" >'list.pl' <<'END_OF_FILE'
X#! /usr/local/bin/perl
X
do "wrl-uumap.pl" || die "can't do wrl-uumap.pl";
X
dbmopen(mapdb, "$uumap'data/mapdb", 0666) || die "can't open mapdb: $!";
X
while (($key,$val) = each(mapdb)) {
X	($name,$dtype) = split($;, $key);
X	printf("%-30s %-8s (%s)\n", $name, $dtype, $val);
X}
X
exit 1;
END_OF_FILE
if test 282 -ne `wc -c <'list.pl'`; then
    echo shar: \"'list.pl'\" unpacked with wrong size!
fi
# end of 'list.pl'
fi
if test -f 'mailpath.sh' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mailpath.sh'\"
else
echo shar: Extracting \"'mailpath.sh'\" \(396 characters\)
sed "s/^X//" >'mailpath.sh' <<'END_OF_FILE'
X#! /bin/sh
X
X[ $# -eq 1 ] || {
X	echo "usage:	$0 person"
X	echo "   or:	$0 person@place"
X	exit 1
X}
X
eval `echo $1 | awk -F@ '
X	{ if (NF==1) print "place=" $1 "; person=PERSON"
X	  else print "place=" $2 "; person=" $1
X	}
X' `
X
set `>BIND</dbm fetch $place >LIBD</paths`
X[ "$2" = "[NOT" ] && {
X	echo mail path to $place not found
X	exit 1
X}
X
echo $person $2 | awk '{ printf($2,$1); print ""; }'
X
exit 0
END_OF_FILE
if test 396 -ne `wc -c <'mailpath.sh'`; then
    echo shar: \"'mailpath.sh'\" unpacked with wrong size!
fi
# end of 'mailpath.sh'
fi
if test -f 'makefile.libd.src' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile.libd.src'\"
else
echo shar: Extracting \"'makefile.libd.src'\" \(1199 characters\)
sed "s/^X//" >'makefile.libd.src' <<'END_OF_FILE'
X# Makefile - for paths &whatnot
X# vix 30may90 [got rid of lots of complexity, converted to unpackmaps]
X# vix 30nov87 [written]
X#
X# This should be modified only in the source directory, probably something
X# like   .../uucpmap/makefile.libd.   If you change the non-source copy, be
X# prepared to have your changes blown away by an unthinking machine...
X
NEWSUSR		=	>NEWSUSR<
X
PATHALIAS	=	>BIND</pathalias
LCASEP		=	>BIND</lcasep
DBM		=	>BIND</dbm
MAPD		=	>MAPD<
X
STAMP		=	$(MAPD)/.update_stamp
MAPFILES	=	[du].*
X
PATHS		=	>LIBD</paths
UUMAP		=	>LIBD</uumap
LOCAL		=	>LIBD</path.local >LIBD</glue.local
X
all		:;	@echo "targets are unbatch, paths, and uumap"
X
unbatch		:;	->LIBD</unpackmaps
X
paths		:	$(PATHS).pag
X
uumap		:	$(UUMAP).pag
X
X$(PATHS).pag	:	$(PATHS)
X			$(DBM) clear newpaths; \
X			$(DBM) -I load $(PATHS) newpaths; \
X			rm -f $(PATHS).dir $(PATHS).pag; \
X			mv newpaths.dir $(PATHS).dir; \
X			mv newpaths.pag $(PATHS).pag
X
X$(PATHS)	:	$(LOCAL) $(STAMP)
X			cd $(MAPD); \
X			$(PATHALIAS) $(LOCAL) $(MAPFILES) \
X				| $(LCASEP) \
X				| sort > >LIBD</newpaths; \
X			mv >LIBD</newpaths $(PATHS)
X
X$(UUMAP).pag	:	$(STAMP)
X			cd >LIBD<; ./mkall
X
X$(STAMP)	:;	touch $(STAMP); chown $(NEWSUSR) $(STAMP)
END_OF_FILE
if test 1199 -ne `wc -c <'makefile.libd.src'`; then
    echo shar: \"'makefile.libd.src'\" unpacked with wrong size!
fi
# end of 'makefile.libd.src'
fi
if test -f 'mkall.pl' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mkall.pl'\"
else
echo shar: Extracting \"'mkall.pl'\" \(399 characters\)
sed "s/^X//" >'mkall.pl' <<'END_OF_FILE'
X#! /usr/local/bin/perl
X
do "wrl-uumap.pl" || die "can't do wrl-uumap.pl: $!";
X
X$| = 1;
X
do "mkmap.pl" || die "can't do mkmap, probably a syntax error in it: $!";
X
unlink "$uumap'data/mapdb.dir", "$uumap'data/mapdb.pag";
X
chop($cwd = `pwd`);
X
chdir "$uumap'maps" || die "can't chdir: $!";
X@maps = <[du].*>;
chdir $cwd;
X
foreach $map (@maps) {
X	print "$map...";
X	&mkmap($map);
X	print "\n";
X}
X
exit 0;
END_OF_FILE
if test 399 -ne `wc -c <'mkall.pl'`; then
    echo shar: \"'mkall.pl'\" unpacked with wrong size!
fi
# end of 'mkall.pl'
fi
if test -f 'mkmap.pl.src' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mkmap.pl.src'\"
else
echo shar: Extracting \"'mkmap.pl.src'\" \(2720 characters\)
sed "s/^X//" >'mkmap.pl.src' <<'END_OF_FILE'
X#
X# $Header:$
X#
X
package mkmap;
X
X($between, $within) = (0, 1);
X
sub main'mkmap {
X
local($map) = @_;
X
dbmopen(mapdb, "$uumap'data/mapdb", 0666) || die "can't open unames database";
if (!open(map,"$uumap'maps/$map")) {
X	warn "mkmap: can't open $map: $!";
X	return;
X}
X
X$input_state = $between;
line: while (<map>) {
X	#
X	# we're looking for a \n\n#N[ \t], which starts a new map entry
X	#
X	if ($input_state == $between) {
X		if (! /^#[Nn]/) {
X			next;
X		}
X		#
X		# found one.  init the things we'll later store in the
X		# database; change input state; parse for names; continue.
X		#
X		$map_position = tell - length($_);
X		$input_state = $within;
X		chop;
X		s/^#N[A-Za-z]*//;
X		s/[ \t]+//g;
X		s/['"]//g;
X		@names = split(/,/);
X
X		#
X		# find the canonical name (the first one without any dots
X		# will do), defaulting to the first entry on the line.
X		#
X		$cname = $names[$[];
X		foreach $name (@names) {
X			if ($name !~ /\./) {
X				$cname = $name;
X				last;
X			}
X		}
X
X		#
X		# another pass through to delete $cname from @names
X	        # (actually we create @aliases from @names but don't
X	        # include the $cname)
X		#
X		undef @aliases;
X		foreach $name (@names) {
X			if ($name ne $cname) {
X				push(@aliases, $name);
X			}
X		}
X
X		#
X		# store the main data for this map entry
X		#
X		$mapdb{$cname,"map"} = join('@', $map, $map_position);
X
X		next;
X	}
X
X	if ($input_state == $within) {
X		if (! /^#[Nn]/) {
X			chop;
X			s/[ \t]+//g;
X			s/['"]//g;
X			if ((! /^#/) && (/=/) && (! /{/) && (/(\w)=(.*)/)) {
X				#
X				# looks like an equate without a {network}
X				#
X				($n, $a) = split(/=/, $_);
X				if ($n eq $cname) {
X					#
X					# looks like it belongs here
X					#
X					foreach $x (split(/,/, $a)) {
X						push(@aliases, $x);
X					}
X				}
X			}
X			next;
X		}
X		#
X		# end of a map entry
X		#
X
X	        # we delayed writing the aliases stuff until now
X	        # because some of the aliases are equates in the
X	        # map entry itself.
X
X		&write_aliases();
X		undef @aliases;
X
X		$input_state = $between;
X		redo line;
X	}
X
X	printf("impossible state found: %d\n", $input_state);
X	die;
X}
X#
X# test for premature eof
X#
if (defined(@aliases)) {
X	print "(premature EOF)";
X	&write_aliases();
X	undef @aliases;
X}
dbmclose(mapdb);
close(map);
X
X} #sub mkmap
X
sub write_aliases {
X##	printf("%s: %d@%s (%s)\n",
X##		$cname, $map_position, $map, join(' ',@aliases));
X
X	#
X	# store an aliases list if there are any aliases
X	#
X	if ($#aliases >= $[) {
X		$mapdb{$cname,"aliases"} = join('@', @aliases);
X	}
X
X	#
X	# store the aliases.  extra fields are probably worthless
X	# but let's leave room for future complexity
X	#
X	foreach $name (@aliases) {
X		# only one field (now) but use join anyway
X		$mapdb{$name,"alias"} = join('@', $cname);
X	}
X} #sub write_aliases
END_OF_FILE
if test 2720 -ne `wc -c <'mkmap.pl.src'`; then
    echo shar: \"'mkmap.pl.src'\" unpacked with wrong size!
fi
# end of 'mkmap.pl.src'
fi
if test -f 'mkone.pl' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mkone.pl'\"
else
echo shar: Extracting \"'mkone.pl'\" \(213 characters\)
sed "s/^X//" >'mkone.pl' <<'END_OF_FILE'
X#! /usr/local/bin/perl
X
do "wrl-uumap.pl" || die "can't do wrl-uumap.pl";
X
X$| = 1;
X
do "mkmap.pl" || die "can't open mkmap.pl: $!";
X
foreach $map (@ARGV) {
X	print "$map...";
X	&mkmap($map);
X	print "\n";
X}
X
exit 0;
END_OF_FILE
if test 213 -ne `wc -c <'mkone.pl'`; then
    echo shar: \"'mkone.pl'\" unpacked with wrong size!
fi
# end of 'mkone.pl'
fi
if test -f 'unpackmaps.sh' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'unpackmaps.sh'\"
else
echo shar: Extracting \"'unpackmaps.sh'\" \(8083 characters\)
sed "s/^X//" >'unpackmaps.sh' <<'END_OF_FILE'
X#! /bin/sh
X
X#	Unpackmaps Copyright 1990, Chris Lewis, All Rights Reserved
X
X# patch 1 (done -> fi) applied
X#
X# hacked 30may90 by vixie to not run pathalias at all, just unpack maps;
X# touches MAPDIR/.update_stamp whenever a map file is updated; is config'd
X# by the makefile now.
X
trap "rm -f /tmp/unp?$$; exit" 0 1 2 3 15
IFS="	 
X"
export IFS
PATH=/usr/ucb:/bin:/usr/bin
export PATH
X
X#	The name of the file that you've caused your news system to
X#	batch the file names of the map articles.
X# Eg: C-news
X#BATCH=/usr/lib/news/batch/b.maps/togo
X#Modern C-news (directory other than /usr/spool/news/out.going)
X#BATCH=/usr/spool/news/out.special/maps/togo
X# Eg: B-news
X#BATCH=/usr/spool/batch/maps
BATCH=>BATCH<
X#	News spool directory
X#NEWSSPOOL=/usr/spool/news
NEWSSPOOL=>NEWSSPOOL<
X#	Where you want the maps to go.
X#	I like using /usr/spool/maps, but on our system, /usr/spool/news
X#	is a separate file system, and /usr runs close to the limit...
X#MAPDIR=/usr/spool/news/maps
MAPDIR=>MAPDIR<
X#	Person to send results and error messages to
X#NOTIFY=clewis
NOTIFY=usenet
X#	pathalias binary
X#PATHALIAS=/usr/lbin/pathalias
X#	where you want the path files to go:
X#	A convenient place is /usr/lib/uucp/paths which is the smail
X#	default.  If you're going to put this in /usr/lib/uucp, I suggest
X#	(rather than make /usr/lib/uucp writeable by everybody), doing
X#	the following:
X#		su root
X#		cd /usr/lib/uucp
X#		touch paths
X#		chown news paths	(or usenet)
X#		chmod 644 paths
X#PATHFILE=/usr/lib/uucp/paths
X#	Auxiliary options to pathalias.  Tune to local tastes....
X#PATHOPTS="-dwatmath"
X#	If you have a version[s] of your machine's map entry that is different 
X#	from what's published, change this variable to point at it/them.
X#	(Eg: I publish the first entry here, and the second one is local tuning
X#	and hidden connections)
X#PATHLOCAL="/usr2/clewis/maps/path.local /usr2/clewis/maps/path.nonpublic"
X#	If this variable is set to the compress binary, maps will be
X#	compressed.
X#COMPRESS=/usr2/clewis/maps/compress12
X#	1 to strip comments from maps - don't do this if you want to use
X#	uuwhere.  However, this is a great space saver...
NOCOMMENTS=0
X#	Define to the name of a file where you want the where database
X#	to be kept.  Undef if you don't want uuwhere at all.
X#WHEREFILE=$MAPDIR/where.db
X#	Uncomment this if you want the map unpacker to remove the
X#	News articles after the maps have been extracted from them.
X#	DO NOT DO THIS IF YOU FORWARD MAP ARTICLES TO OTHER SITES!
X#	This also relies on your awk returning "exit" codes properly.
X#	Yours may not...
X#UNLINK=1
X#	PS: there is *one* possible edit that you might want to make
X#	below - the maps used to generate wierd domains, but most of that
X#	appears to be gone now (don't ask me, I never particularly understood
X#	it, but since Peter Honeyman recommended it...).  If you object
X#	to these wierd domains, uncomment the egrep.
X
X#	Edit no more....
X
umask 022
X
if test ! -d $MAPDIR -o ! -w $MAPDIR
then
X    echo "$MAPDIR missing, unwritable or not a directory" >&2
X    exit 1
fi
X
if test $# = 1
then
X    case $1 in
X	-p)
X	    forcepath=true
X	    ;;
X	-P)
X	    forcepath=false
X	    ;;
X	-i)
X	    cd /
X	    rm -f $BATCH.work
X	    # using find/sort instead of ls just in case there's lots of
X	    # articles....
X	    find $NEWSSPOOL/comp/mail/maps -type f -print | sort > $BATCH
X	    ;;
X	*)
X	    echo "usage: unpackmaps [-i] [-p]" >&2
X	    exit 1
X	    ;;
X    esac
fi
X
cd $MAPDIR
WHERETMP=/tmp/WHERE$$
rm -f $WHERETMP
X	    
while test -f $BATCH -o -f $BATCH.work
do
X    # There is no window of vulnerability here as long as noone else is
X    # creating $BATCH.work.
X    if test ! -f $BATCH.work
X    then
X	mv $BATCH $BATCH.work
X    fi
X
X    while read i stuff
X    do
X	#	Using stuff to capture remaining junk on line.
X	#	Eg: C-news article sizes.
X
X	if test -z "$i"
X	then
X	    break
X	fi
X
X	if test ! -r $i
X	then
X	    echo "$i apparently superseded or expired"
X	    continue
X	fi
X
X	# This awk script depends on the following map article format:
X	# <don't cares>
X	# cat << 'something' > filename
X	# map body
X	# something
X	# <don't cares>
X	# "something" doesn't have to be enclosed in quotes in the cat line.
X	# This isn't particularly fast - could be dramatically speeded up
X	# if written in C, but I was trying to ensure that this is as simple
X	# and self-evident as possible.
X
X	awk '
X	BEGIN	{
X		where = "'"$WHEREFILE"'"
X	    }
X	$1 == "cat" && collecting == 0 {
X		recno = 1
X		endtoken=$3;
X		if (substr(endtoken, 1, 1) == "'"'"'")
X		    endtoken=substr(endtoken, 2, length(endtoken)-2);
X		collecting = 1;
X		foundone = 1;
X		name = $5;
X		if (index(name, "/") != 0) {
X		    printf("Security violation attempt in %s!\n", "'$i'");
X		    exit 1;
X		} else
X		    printf("extracting %s from %s\n", name, "'$i'");
X		next;
X	    }
X
X	    {
X		if (!collecting)
X		    next;
X		if ($1 == endtoken) {
X		    line = "rm -f " name ".Z"
X		    print "" | line
X		    collecting = 0;
X		    next
X		}
X		if ($1 ~ /^#N/ && where) {
X		    for (i = 2; i <= NF; i++) {
X			sname = $i
X			if (p = index(sname, ","))
X			    sname = substr(sname, 1, p-1)
X			printf "@%s %s %d\n", sname, name, recno >> \
X			    "'$WHERETMP'";
X		    }
X		}
X		if ("'$NOCOMMENTS'" == 1 && $0 ~ /#/)
X		    print substr($0, 1, index($0, "#")) > name
X		else {
X		    print $0 > name
X		}
X		recno++
X	    }
X	    
X	    END {
X		if (collecting) {
X		    printf("Non-terminated map in %s\n", "'$i'");
X		    exit 1;
X		}
X		if (!foundone) {
X		    printf("%s does not contain a properly formed map\n", "'$i'");
X		    exit 1;
X		}
X	    }' $i
X
X	touch $MAPDIR/.update_stamp
X
X	if test $? = 0 -a -n "$UNLINK"
X	then
X	    rm -f $i
X	fi
X
X    done < $BATCH.work
X    rm $BATCH.work
done > /tmp/unpA$$ 2>&1
X
if test -n "$COMPRESS"
then
X    files=`ls ?.* | sed -e '/\.Z$/d'`
X    if test -n "$files"
X    then
X	$COMPRESS -f $files
X    fi
fi
X
if test -n "$PATHALIAS" -a -f "$PATHALIAS" -a "$forcepath" != false
then
X    if test -s /tmp/unpA$$ -o "$forcepath" = true
X    then
X	cd $MAPDIR
X
X	(
X	if test -n "$COMPRESS"
X	then
X	    $COMPRESS -dc [ud].*.Z | cat - $PATHLOCAL
X	else
X	    cat [ud].* $PATHLOCAL
X	fi |
X
X	$PATHALIAS -f $PATHOPTS |
X
X	# format of the pathalias -f output is
X	# cost	host	route
X	#
X	# format of a 'paths' file for smail is
X	# host	route	first_hop_cost
X	#
X	# move cost field to end of line:
X
X	sed 's/\(.*\)	\(.*\)	\(.*\)/\2	\3	\1/' |
X
X	# convert target domain/host to lower case:
X
X	#lcasep |
X	
X	# remove some additional wierdnesses (per Peter Honeyman):
X	# You can leave it in or not.
X
X	# egrep -v '(\.(com|edu|mil|gov|net|org|arpa|[a-z][a-z])	.*!.*!)|(.\.(com|edu|mil|gov|net|org|arpa|[a-z][a-z])	)' |
X
X	# sort the stream:
X	
X	sort > /tmp/paths ) > /tmp/unpB$$ 2>&1
X
X	if test ! -s /tmp/paths
X	then
X	    echo "Pathalias failed no map file created" >> /tmp/unpB$$
X	else
X	    cat /tmp/paths > $PATHFILE 2>> /tmp/unpB$$
X	    if test $? != 0
X	    then
X		echo "Copy to $PATHFILE failed" >> /tmp/unpB$$
X	    else
X		rm /tmp/paths
X	    fi
X	    echo "Map remade" >> /tmp/unpB$$
X	    ls -l $PATHFILE >> /tmp/unpB$$
X	fi
X
X	if test -s /tmp/unpB$$
X	then
X	    echo "Pathalias output:" >> /tmp/unpA$$
X	    cat /tmp/unpB$$ >> /tmp/unpA$$
X	fi
X    fi
fi
X
if test -n "$WHEREFILE" -a -s $WHERETMP
then
X    if test ! -f $WHEREFILE
X    then
X	touch $WHEREFILE
X    fi
X
X    # First awk: throws away WHERE references in $WHEREFILE that
X    #	are now in $WHERETMP
X    # Sort: sort by site name
X    # Second awk: coalesce references to same site/file to one line.
X    awk '
X	BEGIN {
X	    mapseen[""] = 1
X	}
X	$1 ~ /^@/ {
X	    printf("%s %s %s\n", substr($1, 2), $2, $3);
X	    mapseen[$2] = 1
X	    next;
X	}
X	{
X	    if (mapseen[$2])
X		next
X	    printf("%s %s %s\n", $1, $2, $3);
X	}' $WHERETMP $WHEREFILE | 
X	sort | 
X	awk '
X	{
X	    if (site != $1 || map != $2) {
X		if (site)
X		    printf("\n");
X		site = $1
X		map = $2
X		printf("%s %s %s", $1, $2, $3);
X	    } else
X		printf(",%s", $3);
X	}
X	END {
X	    printf("\n");
X	}' > /tmp/TMP2
X    
X    if test -s /tmp/TMP2
X    then
X	cat /tmp/TMP2 > $WHEREFILE
X    fi
X    echo "Where database ($WHEREFILE) rebuilt" >> /tmp/unpA$$
fi
rm -f /tmp/TMP2 $WHERETMP
X
if test -s /tmp/unpA$$
then
X    mail $NOTIFY < /tmp/unpA$$
fi
END_OF_FILE
if test 8083 -ne `wc -c <'unpackmaps.sh'`; then
    echo shar: \"'unpackmaps.sh'\" unpacked with wrong size!
fi
# end of 'unpackmaps.sh'
fi
if test -f 'uuhost.sh' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'uuhost.sh'\"
else
echo shar: Extracting \"'uuhost.sh'\" \(31 characters\)
sed "s/^X//" >'uuhost.sh' <<'END_OF_FILE'
X#! /bin/sh
X
exec >LIBD</get $@
END_OF_FILE
if test 31 -ne `wc -c <'uuhost.sh'`; then
    echo shar: \"'uuhost.sh'\" unpacked with wrong size!
fi
# end of 'uuhost.sh'
fi
if test -f 'uupath.sh' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'uupath.sh'\"
else
echo shar: Extracting \"'uupath.sh'\" \(72 characters\)
sed "s/^X//" >'uupath.sh' <<'END_OF_FILE'
X#! /bin/sh
X
for host
do
X	>BIND</dbm fetch $host >LIBD</paths
done
X
exit
END_OF_FILE
if test 72 -ne `wc -c <'uupath.sh'`; then
    echo shar: \"'uupath.sh'\" unpacked with wrong size!
fi
# end of 'uupath.sh'
fi
if test -f 'uupaths.sh' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'uupaths.sh'\"
else
echo shar: Extracting \"'uupaths.sh'\" \(63 characters\)
sed "s/^X//" >'uupaths.sh' <<'END_OF_FILE'
X#! /bin/sh
X
for host
do
X	look -f $host >LIBD</paths
done
X
exit
END_OF_FILE
if test 63 -ne `wc -c <'uupaths.sh'`; then
    echo shar: \"'uupaths.sh'\" unpacked with wrong size!
fi
# end of 'uupaths.sh'
fi
if test -f 'wrl-uumap.pl.src' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'wrl-uumap.pl.src'\"
else
echo shar: Extracting \"'wrl-uumap.pl.src'\" \(148 characters\)
sed "s/^X//" >'wrl-uumap.pl.src' <<'END_OF_FILE'
X# configuration constants for uumap
X
package uumap;
X
X$code = ">CODE<";
X$data = ">DATA<";
X$maps = ">MAPS<";
X
package main;
X
push(@INC, $uumap'code);
END_OF_FILE
if test 148 -ne `wc -c <'wrl-uumap.pl.src'`; then
    echo shar: \"'wrl-uumap.pl.src'\" unpacked with wrong size!
fi
# end of 'wrl-uumap.pl.src'
fi
echo shar: End of shell archive.
exit 0
--
Paul Vixie
DEC Western Research Lab	<vixie@wrl.dec.com>
Palo Alto, California		...!decwrl!vixie