Xref: feenix.metronet.com comp.mail.misc:2021
Path: feenix.metronet.com!news.utdallas.edu!wupost!waikato.ac.nz!comp.vuw.ac.nz!asjl
Newsgroups: comp.mail.misc
Subject: Re: R E P O S T :   I N T E R - N E T W O R K   M A I L   G U I D E
Message-ID: <[email protected]>
From: [email protected] (Andy Linton)
Date: 25 May 1993 02:28:33 GMT
References: <[email protected]>
Distribution: world
Organization: Victoria University, PO Box 600, Wellington, NEW ZEALAND
Keywords: gateways, networks, syntax
NNTP-Posting-Host: bats.comp.vuw.ac.nz
Lines: 343


The reposted guide mentions a perl script to query the document. I got this
from John Chew last year.

andy
--
#!/usr/bin/perl

# inmgq - Inter-Network Mail Guide Query utility
#
# Copyright (C) 1992 by John J. Chew, III <[email protected]>
#
# COPYRIGHT NOTICE
#
# This document is Copyright (C) 1992 by John J. Chew.  All rights reserved.
# Permission for non-commercial distribution is hereby granted, provided
# that this file is distributed intact, including this copyright notice
# and the version information above.  Permission for commercial distribution
# can be obtained by contacting the author.

($rcs_revision = "\$Revision: 1.8 $") =~ s/\$//g;
($rcs_date = "\$Date: 92/07/28 23:39:27 $") =~ s/\$//g;
($rcs_file = "\$RCSfile: inmgq,v $") =~ s/\$//g;

# include libraries
($BASEDIR = $0) =~ s!/[^/]+$!! || ($BASEDIR='.');
require 'getopts.pl';

# log if appropriate
if ( -w "$BASEDIR/inmgq.callers" && ($_ = getpeername(STDIN)) )
 {
 local(@time) = localtime(time);
 local($proto, $port, @address) = unpack('SnC4', $_);
 $time[4]++;
 open(LOG, ">>$BASEDIR/inmgq.callers");
 printf LOG "%d-%02d-%02d %02d:%02d:%02d %d.%d.%d.%d %d\n", @time[5,4,3,2,1,0],
   @address, $port;
 close(LOG);
 }

# check command line
$help = "INMG Query Commands:\n\n".
 "dump                dump a stripped version of the INMG file (long)\n".
 "from [netid...]     list known connections from networks\n".
 "help                list available commands\n".
 "how net1 net2       explain how to send mail from net1 to net2\n".
 "network [netid...]  list information about networks\n".
 "networks            list known networks\n".
 "to [netid...]       list known connections to networks\n".
 "version             show version of INMG file and query utility\n".
 "quit                exit from the program\n".
 "";
$usage = "Usage: $0 [-v] [-f inmg-file] [command [arg...]]\n\n". $help;
die $usage unless &Getopts('f:v');

# look for inmg file in various places
(defined($inmg = $opt_f))
 || (-f ($inmg = "$ENV{'INMG'}"))
 || (-f ($inmg = "$BASEDIR/inmg"))
 || (-f ($inmg = "$ENV{'HOME'}/inmg/inmg"))
 || (-f ($inmg = "$ENV{'HOME'}/doc/inmg"))
 || (-f ($inmg = '/usr/local/doc/inmg'))
 || die "Cannot find inmg file\n";

# welcome user - loadinmg takes some time
$| = 1;
print "Welcome to the Inter-Network Mail Guide\n";
print "\n";
print "Please wait a few seconds while the database loads.\n";

# load the file
&loadinmg($inmg);
print "Thank you.  Type 'help' for a list of commands.\n";

# single command on command line?
if ($#ARGV >= 0) {
 $command = shift;
 die $usage unless eval "defined &do_$command";
 eval "&do_$command(\@ARGV)";
 print $@;
 }
else {
 while (print('inmgq> '),length($_=<>)) {
   split;
   next if $#_ == -1;
   $command = shift @_;
   eval "defined &do_$command"
     || (print ("Enter 'help' to list valid commands.\n"), next );
   eval "&do_$command(\@_)";
   print $@;
   }
 print "\n";
 }
exit 0;

## subroutines follow in alphabetical order

# &check_netid - check a network id
sub check_netid {
 for $netid (@_) {
   die "I do not know of a network called '$netid'.\n".
     "Use the 'networks' command to list known networks.\n"
     unless defined $netname{$netid};
   }
 }

# &do_dump - process 'dump' command
sub do_dump { local($_, $from, $how, $key, $net, $to);
 die "Usage: $0 dump\n" if $#_ != -1;
 for $net (sort keys %netname) {
   &wrap("#N $net;$netname{$net};$netorg{$net};$nettype{$net};$netnote{$net}");
   }
 print "\n";
 for $key (sort keys %how) {
   ($from, $to) = ($key =~ /(.*) (.*)/);
   print "#F $from\n#T $to\n#R $recvr{$key}\n";
   print "#C $contact{$key}\n" if defined $contact{$key};
   for $how (split("\n",$how{$key})) { &wrap("#I $how"); }
   print "\n";
   }
 }

# &do_from - process 'from' command
sub do_from { local(@argv) = @_; local($from);
 for $from (($#argv == -1) ? sort keys %from: @argv)
   { &fmt($from{$from}, "$from: ", "  "); }
 }

# &do_help - process 'help' command
sub do_help { print $help; }

# &do_how - process 'how' command
sub do_how {
 local($from, $to) = @_;
 local($key) = "$from $to";
 local($how);

 die "Usage: how net1 net2\n" unless $#_ == 1;
 &check_netid($from, $to);
 defined $how{$key}
   || die "There is no known gateway from $netname{$from} to $netname{$to}.\n";
 &fmt("How to send mail from $netname{$from} to $netname{$to}:", '', '  ');
 &fmt("(For further information contact $contact{$key})", '  ', '    ')
   if defined $contact{$key};
 &fmt("To send mail to '$recvr{$key}'", '  ', '    ');
 for $how (split("\n", $how{$key})) { &fmt($how, '  - ', '    '); }
 }

# &do_network - process 'network' command
sub do_network { local(@argv) = @_; local($net);
 &check_netid(@argv);
 for $net (($#argv == -1) ? sort keys %netname : @argv) {
   print "$net:\n  Full Name:    $netname{$net}\n".
     "  Organization: $netorg{$net}\n  Type:         $nettype{$net}\n";
   print "  Notes:        $netnote{$net}\n" if length($netnote{$net});
   print "\n";
   }
 }

# &do_networks - process 'networks' command
sub do_networks { die "Usage: networks\n" if $#_ != -1;
 &fmt(join(' ', sort keys %netname, '', ''));
 }

# &do_quit - process 'quit' command
sub do_quit { exit 0; }

# &do_rerun - process secret 'rerun' command
sub do_rerun { exec $0; }

# &do_to - process 'to' command
sub do_to { local(@argv) = @_; local($to);
 for $to (($#argv == -1) ? sort keys %to: @argv)
   { &fmt($to{$to}, "$to: ", "  "); }
 }

# &do_version - process 'version' command
sub do_version { die "Usage: version\n" if $#_ != -1;
 print "Inter-Network Mail Guide file:\n";
 print "  ", join("\n  ", @version), "\n";
 print "Inter-Network Mail Guide query utility:\n";
 print "  $rcs_revision\n  $rcs_date\n";
 }

# &fmt($string, $ind1, $ind2) - display a string, wrapping at word breaks to
#   80 columns max, indenting first line by ind1 and subsequent lines by ind2.
sub fmt {
 local($_, $ind1, $ind2) = @_;
 local($break, $hyphen, $measure, $space);

 $ind = $ind1; s/^ +//; s/ +$//;
 while (1) {
   print $ind;
   $measure = 80 - length($ind);
   if (length($_) < $measure) { print "$_\n"; last; }
   $hyphen = rindex($_, '-', $measure);
   $space = rindex($_, ' ', $measure);
   $break = ($hyphen > $space) ? $hyphen : $space;
   $break = $measure if $break == -1;
   print substr($_, 0, $break), "\n";
   substr($_, 0, $break) = '';
   s/^ +//;
   $ind = $ind2;
   last unless length;
   }
 }

# &getblock - read a block of records skipping comments, returns values in
#   @tags and @data.
sub getblock {
 local($tag, $data);
 @tags = @data = ();
 while (!$eof)
   {
   &getrecord;
   defined $tag || (($#tags >= 0) ? last : next);
   next if $tag eq '';
   push(@tags, $tag);
   push(@data, $data);
   }
 }

# &getline - read a line with one line of pushback, returns results in $linetag
#   and $linedata.  Also uses $eof, $pushback and $_.
$eof = 0;
$pushback = undef;
sub getline {
 $linetag = undef;
 $linedata = '';
 while (1) {
   defined($_ = $pushback) ? ($pushback = undef) : ($_ = <INMG>);
   if (! defined $_) { $eof = 1; return; }
   die "Line $. not terminated by newline\n" unless /\n$/;
   return if length == 1;
   die "Line $. too long\n" if length > 81;
   die sprintf("Illegal character \\%03d in line $..\n", ord($1))
     if /([^ -~\n])/;
   (($opt_v && &parsefailed("discarding garbage line")), next) if /^[^#]/;
   last;
   }
 ($linetag, $linedata) = /^#([^ \n]*) ?(.*)$/;
 }

# &getrecord - read a record, joining continuation lines, returns results in
#   $tag and $data.
sub getrecord {
 local($linetag, $linedata, $_);
 local($result);

 &getline;
 $tag = $linetag;
 ($data = $linedata) =~ s/^ +//;
 return unless defined $tag;
 die "Illegal continuation at line $..\n" if $tag eq '-';

 while (1) {
   &getline;
   if ($linetag eq '-') { $data .= $linedata; }
   else { $pushback = $_; last; }
   }
 }

# &loadinmg($filename) - load the inmg file into memory
sub loadinmg {
 local($data, $hascontact, $key, $lastfrom, $lastto, $tag, @_);

 # open file
 open(INMG, "<$inmg") || die "Cannot open $inmg ($!)\n";

 # load and check version block
 &getblock;
 for $tag (@tags)
   { &parsefailed("Unexpected tag in version block: '#$tag'") if $tag ne 'V'; }
 @version = @data;
 for $data (@version) { $data =~ s/\$//g; }

 # load and check network block
 &getblock;
 for $tag (@tags)
   { &parsefailed("Unexpected tag in network block: '#$tag'") if $tag ne 'N'; }
 for $data (@data) {
   split(/ *; */, $data, 10);
   ($#_ == 4) || &parsefailed("Bad field count in: $data");
   ($_[0] eq '') && &parsefailed("Missing network identifier in: $data");
   ($_[1] eq '') && &parsefailed("Missing network full name in: $data");
   ($_[2] eq '') && &parsefailed("Missing network organization in: $data");
   ($_[3] =~
     /^(academic|bbs|commercial|government|in-house|non-profit|none|\?)$/)
     || &parsefailed("Bad network type in: $data");
   $netname{$_[0]} = $_[1];
   $netorg{$_[0]} = $_[2];
   $nettype{$_[0]} = $_[3];
   $netnote{$_[0]} = $_[4];
   }

 # load and check the rest of the blocks
 $lastfrom = $lastto = '';
 while (&getblock, !$eof) {
   $hascontact = ($tags[3] eq 'C');
   if (defined($from{$data[0]}))
     { $from{$data[0]} .= " $data[1]" if $from{$data[0]} !~ / $data\[1]$/; }
   else { $from{$data[0]} = "$data[1]"; }
   if (defined($to{$data[1]}))
     { $to{$data[1]} .= " $data[0]" if $to{$data[1]} !~ / $data\[0]$/; }
   else { $to{$data[1]} = "$data[0]"; }
   $key = "$data[0] $data[1]";
   $recvr{$key} = $data[2];
   $contact{$key} = $data[3] if $hascontact;
   $how{$key} = join("\n", @data[($hascontact?4:3)..$#data]);
   ($#tags < 3) && &parsefailed("block too short");
   ($tags[0] eq 'F') || &parsefailed("bad first tag: '$tags[0]'");
   ($tags[1] eq 'T') || &parsefailed("bad second tag: '$tags[1]'");
   ($tags[2] eq 'R') || &parsefailed("bad third tag: '$tags[2]'");
   ($tags[3] =~ /^[CI]$/) || &parsefailed("bad fourth tag: '$tags[3]'");
   for $tag (@tags[4..$#tags])
     { ($tag eq 'I') || &parsefailed("bad tag: '$tag'"); }
   ($data[0] < $lastfrom) &&
     &parsefailed("source network out of order: $data[0]");
   (defined $netname{$data[0]}) ||
     &parsefailed("unknown source network: $data[0]");
   ($data[1] < $lastto) &&
     &parsefailed("destination network out of order: $data[1]");
   (defined $netname{$data[1]}) ||
     &parsefailed("unknown destination network: $data[1]");
   $lastto = ($lastfrom eq $tags[0]) ? $tags[1] : '';
   $lastfrom = $tags[0];
   }
 close(INMG);
 }

# &parsefailed($reason) - die because the inmg file couldn't be parsed
sub parsefailed {
 &fmt("$0: $inmg at or before line $.: $_[0]", '', '');
 exit 1;
 }

# &wrap($text) - print text wrapping to 80 columns with INMG continuations
sub wrap { local($_) = @_;
 print substr($_, 0, 80), "\n";
 substr($_, 0, 80) = '';
 while (length)
   { print "#- ", substr($_, 0, 77), "\n"; substr($_, 0, 77) = ''; }
 }