Xref: utzoo alt.sources:2603 comp.mail.misc:4333 Path: utzoo!utgpu!cs.utexas.edu!sun-barr!newstop!texsun!convex!convex.COM From: tchrist@convex.COM (Tom Christiansen) Newsgroups: alt.sources,comp.mail.misc Subject: Re: Alias Lister For Users Message-ID: <108922@convex.convex.com> Date: 18 Nov 90 14:35:56 GMT References: <1990Nov17.023351.16824@lokkur.dexter.mi.us> <1990Nov18.020554.17860@mp.cs.niu.edu> <1990Nov18.055118.28281@lokkur.dexter.mi.us> Sender: news@convex.com Reply-To: tchrist@convex.COM (Tom Christiansen) Followup-To: alt.sources.d Organization: CONVEX Software Development, Richardson, TX Lines: 424 I haven't posted these in a while, and they've grown a bit since last time. It does recursively resolve aliases, including following include files and .forward files, and is pretty faster. pixel% getalias -V postmaster [ postmaster -> root ] [ root -> //.forward ] [ //.forward -> rhall, rmingee, tchrist ] [ rhall -> rhall@pixel ] [ rhall -> /mnt/rhall/.forward ] [ /mnt/rhall/.forward -> "| /usr/local/mh/lib/slocal -user rhall" ] [ rmingee -> rmingee@pixel ] [ tchrist -> tchrist@pixel ] postmaster -> "| /usr/local/mh/lib/slocal -user rhall", rmingee, tchrist (stripped of @pixel at the end because that's where I ran the query.) Also included is nfinger, which uses the same algorithm and fingers the results of the alias expansion. It passes finger switches on to finger. I often due this to find out who's logged in from a particular project group: % alias fu 'nfinger -sm' % fu mailing-list Getalias has an embedded man page, so install /usr/local/bin/getalias as a link to /usr/local/man/man1/getalias, or whatever your local paths are. Nfinger doesn't -- Use the Source. ps: I admit to no longer recalling why nfinger didn't just call getalias. --tom #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # getalias # nfinger # This archive created: Sun Nov 18 08:32:39 1990 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'getalias'" '(4807 characters)' if test -f 'getalias' then echo shar: "will not over-write existing file 'getalias'" else sed 's/^ X//' << \SHAR_EOF > 'getalias' X#!/usr/local/bin/perl X'di'; X'ig00'; X Xdbmopen(ALIASES,'/usr/lib/aliases',undef) || die "can't dbmopen aliases"; X Xrequire 'getopts.pl';; X X(&Getopts('vVs') && $#ARGV >= 0) || die "usage: $0 [-vVs] alias ...\n"; X Xchop($host = `hostname`); X X($verbose, $showall, $short) = ($opt_v, $opt_V, $opt_s); X$verbose |= $showall; X Xwhile ($user = shift) { X local(%seen); X if ($short) { X print join(' ', &resolve($user)), "\n"; X } else { X print "$user -> ", join(', ', sort &resolve($user)), "\n"; X } X} X Xsub resolve { X local($addr,$alias,@list,@ilist); X X while ($addr = shift) { X if ($seen{$addr}++) { X #push(@list, $addr); X next; X } X unless (defined $ALIASES{"$addr\0"}) { X push(@list, &forward($addr)); X next; X } X chop($alias = $ALIASES{"$addr\0"}); X $alias =~ s/^\s*(.*)\s*$/$1/; X if ($alias eq $addr) { X push(@list, &forward($addr)); X next; X } X if ($alias =~ /^"/) { X push(@list, $alias); X next; X } X print "[ $addr -> $alias ]\n" X if $showall || ($verbose X && ($alias !~ /^$addr@\w+$/ && X $alias !~ /^[^!]+![^!]+$/)); X if ($alias eq "$addr@$host") { X push(@list, &forward($addr)); X next; X } X if ($alias =~ /^:include:(.*)/) { X unless (open(INC, $file = $1)) { X print STDERR "$0: can't open $file: $!\n"; X next; X } X @ilist = grep(!/^#/, ); X for (@ilist) { s/\s//g; } X close(INC); X printf "[ %s -> %s ]\n", $file, join(' ', @ilist) if $verbose; X push(@list,&resolve(@ilist)); X } else { X push(@list,&resolve(split(/\s*,\s*/,$alias))); X } X } X return @list; X} X X X############################################################## X Xsub forward { X local($user) = @_; X local($forward); X X return $user if $user =~ /^\s*"?[|\/]/; X return $user if $user =~ /^\s*.+@.+$/; X return $user if $user =~ /^\s*.+\\?!.+$/; X return $user if $user =~ /^\s*\\/; X X if (($forward = &logdir($user)) && -r $forward .= '/.forward') { X if (!open forward) { X print STDERR "$0: cannot open $forward: $!\n"; X } else { X print "[ $user -> $forward ]\n" if $verbose; X chop($user = ); X close forward; X print "[ $forward -> $user ]\n" if $verbose; X return &resolve(split(/\s*,\s*/,$user)); X } X } else { X #print "no forward for $user\n"; X } X $user = "$user " unless $forward; X return $user; X X} X X############################################################## X Xsub logdir { X if (! $been_here_before++) { # might make it much faster X setpwent unless $dbm_passwd = dbmopen(PASSWD,'/etc/passwd', undef); X } X X if ($dbm_passwd) { X return '' unless defined $PASSWD{$_[0]}; X local(@a); X @a = split(/[\000]+/,$PASSWD{$_[0]}); X return $a[$#a-1]; X } else { X return (getpwnam($_[0]))[7]; X } X} X############################################################################## X X # These next few lines are legal in both Perl and nroff. X X.00; # finish .ig X X'di \" finish diversion--previous line must be blank X.nr nl 0-1 \" fake up transition to first page again X.nr % 0 \" start at page 1 X';<<'.ex'; #__END__ ############# From here on it's a standard manual page ############ X.TH GETALIAS 1L X.de M \" man page reference X\\fI\\$1\\fR\\|(\\$2\)\\$3 X.. X.SH NAME Xgetalias \- recursively resolve mail aliases X.SH SYNOPSIS X.B getalias X[ X.B \-v X.B \-V X.B \-s X] X.I alias X\&... X.SH DESCRIPTION XThe X.I getalias Xprogram consults the X.M dbm 3X Xversion of the X.M aliases 5 Xdatabase to rescursively resolve each of its arguments, printing Xthe alias's (alphabetically sorted) resolution to the standard output, Xseparated by commas. XInclude Xfiles referenced by the \fI:include:\fP syntax will be consulted, Xas will local users' X.I ~/.forward Xfiles. X.PP XArguemnts not appearing to be deliverable addresses Xare resolved to Xthe form ``\fIalias-name\fP '' to indicate Xthat such mail will probably be delivered to the mailer daemon Xfor subsequent complaint. X.PP XThe X.B \-v Xoption traces intermediary passes of the alias resolution for Xmailing lists. XWatching the recursion can occasionally be entertaining and informative. X.PP XThe X.B \-V Xoption is like X.B \-v\c X, except that it also includes simple ``name -> name@host'' aliases as well. XThese are mailboxes that simply go to another machine, rather than Xmailing lists requiring recursive expansion. X.PP XThe X.B \-s Xoption suppresses printing of the original alias before its resolution. XIt also makes space the separator character. X.SH NOTES X.I Getalias Xis a X.I perl Xprogram, so you must have X.I perl Xon your system to run it. Since it Xis not compiled, you may read the program to learn more about Xhow it works internally. X.SH "SEE ALSO" X.M mail 1 , X.M nfinger 1 , X.M perl 1 , X.M dbm 3X , X.M aliases 5 , X.M sendmail 8 X.SH AUTHOR XTom Christiansen X.I "" X.ex SHAR_EOF if test 4807 -ne "`wc -c < 'getalias'`" then echo shar: "error transmitting 'getalias'" '(should have been 4807 characters)' fi chmod 775 'getalias' fi echo shar: "extracting 'nfinger'" '(3329 characters)' if test -f 'nfinger' then echo shar: "will not over-write existing file 'nfinger'" else sed 's/^ X//' << \SHAR_EOF > 'nfinger' X#!/usr/local/bin/perl X# X# nfinger -- finger people at their home machines X# as defined in the /usr/lib/aliases X# dbm file. recursively resolve all X# aliases first, so works on lists X Xdbmopen(ALIAS,'/usr/lib/aliases',undef) || die "can't dbmopen aliases: $!"; X Xchop($localhost = `hostname`); X X@finger_opts = (); Xwhile ($ARGV[0] =~ /^-/) { X if ($ARGV[0] eq '-v') { X $verbose++; X shift; X } else { X push(@finger_opts, shift); X } X} X Xwhile ($user = shift) { X undef %seen; X $seeking++; X push(@finger, &resolve($user)); X} X Xundef %seen; X@ofinger = @finger; Xfor (@finger) { X s/^\\//; X s/\s//g; X push(@nfinger, $_) unless $seen{$_}++ || m#^\s*("\s*)?[|/]#; X} X@finger = sort @nfinger; X Xif ($seeking && !@finger) { X printf STDERR "$0: can't finger only pipes and files! (@ofinger)\n"; X exit 1; X} X X$exec = "/usr/ucb/finger @finger_opts @finger\n"; X Xprint $exec if $verbose; X X Xexec $exec unless grep(/-.*s/, @finger_opts); X X Xopen (FINGER, "$exec 2>&1 |") || die "Can't open finger pipe\n"; X X$mask = "%-8s%s"; X$\ = "\n"; X$| = 1; X$localhost = sprintf("%-8s", $localhost); X Xwhile () { X s/\s*$//; X next if /^$/; X if (/^\[([^\]]*)\]$/) { X $host = sprintf("%-8s", $1); X $sawhost = 1; X } elsif (/^Login/) { X if (!$printed++) { X substr($_, 9, 0) = 'Home '; X s/ Name/Name /; X print; X } X $host = $localhost unless $sawhost; X $sawhost = 0; X } elsif (/^\S+:/) { X $sawhost = /^finger:/; X print STDERR "$host <$_>"; X } else { X substr($_, 9, 0) = $host; X print; X } X} Xclose FINGER || die "$0: error running finger, status was $?\n"; X X############################################################## X Xsub resolve { X local($addr,$alias,@list); X local(@addrs) = @_; X X for $addr (@addrs) { X unless (defined $ALIAS{"$addr\0"}) { X push(@list, &forward($addr)); X next; X } X chop($alias = $ALIAS{"$addr\0"}); X X $alias =~ s/^\s*(.*)\s*$/$1/; X $alias =~ s/^([^!]*)!([^!]+)$/$2@$1/; X X if ($alias eq "$addr@$localhost" || $alias eq $addr) { X push(@list, &forward($addr)); X } else { X print "[ $addr -> $alias ]\n" if $verbose; X push(@list,&resolve(split(/\s*,\s*/,$alias))); X } X } X return @list; X} X X X############################################################## X Xsub forward { X local($user) = @_; X local($forward); X X $seen{$addr}++ && return $addr; X X return $user if $user =~ /^\s*"?[|\/]/; X return $user if $user =~ /^\s*.+@.+$/; X return $user if $user =~ /^\s*.+\\?!.+$/; X return $user if $user =~ /^\s*\\/; X X if (($forward = &logdir($user)) && -r $forward .= '/.forward') { X if (!open forward) { X print STDERR "$0: cannot open $forward: $!\n"; X } else { X print "[ $user -> $forward ]\n" if $verbose; X chop($user = ); X close forward; X print "[ $forward -> $user ]\n" if $verbose; X return &resolve(split(/,/,$user)); X } X } X return $user; X X} X X############################################################## X Xsub logdir { X if (! $been_here_before++) { # might make it much faster X setpwent unless $dbm_passwd = dbmopen(PASSWD,'/etc/passwd', undef); X } X X if ($dbm_passwd) { X return '' unless defined $PASSWD{$_[0]}; X local(@a); X @a = split(/[\000]+/,$PASSWD{$_[0]}); X return $a[$#a-1]; X } else { X return (getpwnam($_[0]))[7]; X } X} SHAR_EOF if test 3329 -ne "`wc -c < 'nfinger'`" then echo shar: "error transmitting 'nfinger'" '(should have been 3329 characters)' fi chmod 775 'nfinger' fi exit 0 # End of shell archive