-#!/usr/bin/perl --
-
-use POSIX;
-
-setup();
-read_config();
-read_services();
-parse_query();
-process_query();
-
-sub process_query () {
- if (exists $services{$query}) {
-
- exec ($verbose && length $services{$query}->{'verbose'} ?
- $services{$query}->{'verbose'} :
- $services{$query}->{'command'});
- die $!;
-
- }
-
- if ($query eq '/') {
-
- print ("userv fingerd on $hostname\r\n".
- "queries supported:\r\n".
- "\r\n".
- " <nothing> list of logged on users and available services\r\n".
- " / this help text\r\n".
- " <service> separately advertised special finger service\r\n".
- " <user> user (logged in or otherwise)\r\n".
- " <user>+<xtra> user-provided extended/special finger service\r\n".
- " /<substring> search for user matching substring\r\n")
- or die $!;
-
- return;
-
- }
-
- if (!length $query) {
-
- read_per_user();
-
- if ($verbose) {
- print "Username Idle Msg,tty Login at From\r\n" or die $!;
- }
-
- open W,"who -iw|" or die $!;
- while (<W>) {
-
- m/^(\w+) +(\S) +(\S+) +(\w+ +\d+ \d\d\:\d\d) +(\S+) +(.*)$/ or die;
- ($user, $mesg, $tty, $login, $idle, $from) = ($1,$2,$3,$4,$5,$6);
- $mesg = $mesg =~ m/[-+]/ ? $& : '?';
-
- if ($tty =~ m/\./) {
- $from =~ s/.$/$& /;
- $from.= $tty;
- $tty= '';
- }
-
- $pref= exists $user_pref_list{$user}
- ? $user_pref_list{$user} : $def_pref_list;
- next unless $pref =~ m/^\+/;
-
- $idle= '' unless $pref =~ m/i/;
- $mesg= ' ' unless $pref =~ m/m/;
- $tty= '' unless $pref =~ m/t/;
- $login= '' unless $pref =~ m/l/;
- $from= '' unless $pref =~ m/t/;
-
- if ($verbose) {
-
- printf "%-8s %-5s %s%-8s %-12s %s\r\n",
- $user, $idle, $mesg, $tty, $login, $from
- or die $!;
- } else {
- $users{$user}->{'pref'} = $pref;
- $users{$user}->{'mesg'}->{$mesg} = 1;
- $users{$user}->{'idle'} = min_idle($users{$user}->{'idle'}, $idle);
- }
-
- }
- $!=0; close W; $? and die "$! $?";
-
- if (!$verbose) {
- print "Username Idle Msg Name\r\n" or die $!;
-
- for $user (sort keys %users) {
- $pref= $users{$user}->{'pref'};
- $name= $pref =~ m/n/ ? (getpwnam($user))[6] : '';
- $name =~ s/,.*//;
- $mesg= join('', sort keys %{ $users{$user}->{'mesg'} });
- $mesg= '+' if $mesg =~ m,\+,;
- printf "%-8s %-5s %s %s\r\n",
- $user, $users{$user}->{'idle'}, $mesg, $name
- or die $!;
- }
- }
-
- foreach $service (sort keys %services) {
- $desc= $services{$service}->{'desc'};
- next unless length $desc;
-
- if (!$anyservice) {
- print "\r\nService Description\r\n" or die $!;
- $anyservice= 1;
- }
-
- printf "%-12s %s\r\n", $service, $desc or die $!;
- }
-
- print "\r\nFor help, finger /\@$hostname\r\n";
- return;
-
- }
-
- if ($query =~ s,^/,,) {
- $query =~ s/\W/\\$&/g;
- read_per_user();
-
- while (($user,$passwd,$uid,$gid,$quota,$comment,$name) = getpwent) {
- $name =~ s/,.*//;
-
- $pref= exists $user_pref_search{$user}
- ? $user_pref_search{$user}
- : $def_pref_search;
- next unless $pref =~ m/[uy]/;
- $name= '' unless $pref =~ m/y/;
- next unless query_match($user) || query_match($name);
-
- if (!$found) {
- print "Username Name\r\n" or die $!;
- $found= 1;
- }
- printf "%-9s %s\r\n", $user,$name or die $!;
-
- }
-
- if (!$found) {
- print "No matches. finger /\@$hostname for help.\r\n" or die $!;
- }
-
- return;
- }
-
- if ($query =~ s/\+.*$//) { $qsuffix= $&; }
-
- if (!(($user)= getpwnam($query))) {
- print "No user named \`$query'. finger /\@$hostname for help.\r\n" or die $!;
- return;
- }
-
- @servcmd= length $qsuffix
- ? ('finger-finger')
- : ('finger-extended',$qsuffix);
- exec 'userv','-t',300,$user,@list;
- die $!;
-
-}
-
-sub query_match ($) {
- my ($data) = @_;
- return $data =~ m/\b$query\b/io;
-}
-
-sub setup () {
- $progname= $0; $progname =~ s,.*/,,;
- alarm(300);
-
- $config= '/etc/finger-userv/config';
-
- if (@ARGV) { @ARGV == 1 or die; $config= $ARGV[1]; }
- $services= '/etc/userv/finger/services';
- $peruser= '/var/lib/userv/finger/prefs';
- $def_pref_list= '+m'; $list_fields= 'imtlfn';
- $def_pref_search= 'y'; $search_opts= 'nuy';
-}
-
-sub parse_query () {
- $query= <STDIN>;
- $query =~ s/\r?\n$// or die "$0: no query\n";
-
- $verbose = $query =~ s,^/[wW],,;
- $query =~ s/^ *//;
-}
-
-sub min_idle ($$) {
- my ($a,$b) = @_;
- return '.' if $a eq '.' || $b eq '.';
- return $b if $a eq 'old' || $a eq '';
- return $a if $b eq 'old' || $b eq '';;
- return $a le $b ? $a : $b;
-}
-
-sub read_config () {
- if (open C, "$config") {
- while (<C>) {
- chomp; s/\s+$//; s/^\s+//;
- if (m/^default\-pref\s+([-+][$list_fields]+)\s+([$search_opts])$/) {
- $def_pref_list= $1;
- $def_pref_search= $2;
- } elsif (m/^hostname\s+(\S+)$/) {
- $hostname= $1;
- } elsif (m/^prefs\-file\s+(\S.*)$/) {
- $peruser= $1;
- } elsif (m/^services\-file\s+(\S.*)$/) {
- $services= $1;
- } elsif (m/\S/ && !m/^\#/) {
- die;
- }
- }
- close C or die $!;
- } elsif ($! != &ENOENT) {
- die $!;
- }
-
- if (!defined $hostname) {
- chomp($hostname= `hostname -f`);
- length $hostname or die $?;
- }
-}
-
-sub read_services () {
- if (open C, "$services") {
- while (<C>) {
- chomp; s/\s+$//; s/^\s+//;
- next if m/^\#/ || !m/\S/;
- if (m/^service\s+(\S.*)$/) {
- $sname= $1;
- die if exists $services{$sname};
- } elsif (m/^(desc|command|verbose)\s+(\S.*)$/) {
- die if exists $services{$sname}->{$1};
- $services{$sname}->{$1}= $2;
- } else {
- die;
- }
- }
- close C;
- foreach $sname (keys %services) {
- die unless exists $services{$sname}->{'command'};
- }
- } elsif ($! != &ENOENT) {
- die $!;
- }
-}
-
-sub read_per_user () {
- if (open DL, "$peruser") {
- while (<DL>) {
- m/^(\w+) ([-+][$list_fields]+) ([$search_opts])$/ or die;
- $user_pref_list{$1}= $2;
- $user_pref_search{$1}= $3;
- }
- close DL;
- } elsif ($! != &ENOENT) {
- die $!;
- }
-}