Print "still open" messages.
[userv-utils] / finger / in.fingerd
1 #!/usr/bin/perl --
2
3 use POSIX;
4
5 setup();
6 read_config();
7 read_services();
8 parse_query();
9 process_query();
10
11 sub process_query () {
12 if (exists $services{$query}) {
13
14 exec ($verbose && length $services{$query}->{'verbose'} ?
15 $services{$query}->{'verbose'} :
16 $services{$query}->{'command'});
17 die $!;
18
19 }
20
21 if ($query eq '/') {
22
23 print ("userv fingerd on $hostname\r\n".
24 "queries supported:\r\n".
25 "\r\n".
26 " <nothing> list of logged on users and available services\r\n".
27 " / this help text\r\n".
28 " <service> separately advertised special finger service\r\n".
29 " <user> user (logged in or otherwise)\r\n".
30 " <user>+<xtra> user-provided extended/special finger service\r\n".
31 " /<substring> search for user matching substring\r\n")
32 or die $!;
33
34 return;
35
36 }
37
38 if (!length $query) {
39
40 read_per_user();
41
42 if ($verbose) {
43 print "Username Idle Msg,tty Login at From\r\n" or die $!;
44 }
45
46 open W,"who -iw|" or die $!;
47 while (<W>) {
48
49 m/^(\w+) +(\S) +(\S+) +(\w+ +\d+ \d\d\:\d\d) +(\S+) +(.*)$/ or die;
50 ($user, $mesg, $tty, $login, $idle, $from) = ($1,$2,$3,$4,$5,$6);
51 $mesg = $mesg =~ m/[-+]/ ? $& : '?';
52
53 if ($tty =~ m/\./) {
54 $from =~ s/.$/$& /;
55 $from.= $tty;
56 $tty= '';
57 }
58
59 $pref= exists $user_pref_list{$user}
60 ? $user_pref_list{$user} : $def_pref_list;
61 next unless $pref =~ m/^\+/;
62
63 $idle= '' unless $pref =~ m/i/;
64 $mesg= ' ' unless $pref =~ m/m/;
65 $tty= '' unless $pref =~ m/t/;
66 $login= '' unless $pref =~ m/l/;
67 $from= '' unless $pref =~ m/t/;
68
69 if ($verbose) {
70
71 printf "%-8s %-5s %s%-8s %-12s %s\r\n",
72 $user, $idle, $mesg, $tty, $login, $from
73 or die $!;
74 } else {
75 $users{$user}->{'pref'} = $pref;
76 $users{$user}->{'mesg'}->{$mesg} = 1;
77 $users{$user}->{'idle'} = min_idle($users{$user}->{'idle'}, $idle);
78 }
79
80 }
81 $!=0; close W; $? and die "$! $?";
82
83 if (!$verbose) {
84 print "Username Idle Msg Name\r\n" or die $!;
85
86 for $user (sort keys %users) {
87 $pref= $users{$user}->{'pref'};
88 $name= $pref =~ m/n/ ? (getpwnam($user))[6] : '';
89 $name =~ s/,.*//;
90 $mesg= join('', sort keys %{ $users{$user}->{'mesg'} });
91 $mesg= '+' if $mesg =~ m,\+,;
92 printf "%-8s %-5s %s %s\r\n",
93 $user, $users{$user}->{'idle'}, $mesg, $name
94 or die $!;
95 }
96 }
97
98 foreach $service (sort keys %services) {
99 $desc= $services{$service}->{'desc'};
100 next unless length $desc;
101
102 if (!$anyservice) {
103 print "\r\nService Description\r\n" or die $!;
104 $anyservice= 1;
105 }
106
107 printf "%-12s %s\r\n", $service, $desc or die $!;
108 }
109
110 print "\r\nFor help, finger /\@$hostname\r\n";
111 return;
112
113 }
114
115 if ($query =~ s,^/,,) {
116 $query =~ s/\W/\\$&/g;
117 read_per_user();
118
119 while (($user,$passwd,$uid,$gid,$quota,$comment,$name) = getpwent) {
120 $name =~ s/,.*//;
121
122 $pref= exists $user_pref_search{$user}
123 ? $user_pref_search{$user}
124 : $def_pref_search;
125 next unless $pref =~ m/[uy]/;
126 $name= '' unless $pref =~ m/y/;
127 next unless query_match($user) || query_match($name);
128
129 if (!$found) {
130 print "Username Name\r\n" or die $!;
131 $found= 1;
132 }
133 printf "%-9s %s\r\n", $user,$name or die $!;
134
135 }
136
137 if (!$found) {
138 print "No matches. finger /\@$hostname for help.\r\n" or die $!;
139 }
140
141 return;
142 }
143
144 if ($query =~ s/\+.*$//) { $qsuffix= $&; }
145
146 if (!(($user)= getpwnam($query))) {
147 print "No user named \`$query'. finger /\@$hostname for help.\r\n" or die $!;
148 return;
149 }
150
151 @servcmd= length $qsuffix
152 ? ('finger-finger')
153 : ('finger-extended',$qsuffix);
154 exec 'userv','-t',300,$user,@list;
155 die $!;
156
157 }
158
159 sub query_match ($) {
160 my ($data) = @_;
161 return $data =~ m/\b$query\b/io;
162 }
163
164 sub setup () {
165 $progname= $0; $progname =~ s,.*/,,;
166 alarm(300);
167
168 $config= '/etc/finger-userv/config';
169
170 if (@ARGV) { @ARGV == 1 or die; $config= $ARGV[1]; }
171 $services= '/etc/userv/finger/services';
172 $peruser= '/var/lib/userv/finger/prefs';
173 $def_pref_list= '+m'; $list_fields= 'imtlfn';
174 $def_pref_search= 'y'; $search_opts= 'nuy';
175 }
176
177 sub parse_query () {
178 $query= <STDIN>;
179 $query =~ s/\r?\n$// or die "$0: no query\n";
180
181 $verbose = $query =~ s,^/[wW],,;
182 $query =~ s/^ *//;
183 }
184
185 sub min_idle ($$) {
186 my ($a,$b) = @_;
187 return '.' if $a eq '.' || $b eq '.';
188 return $b if $a eq 'old' || $a eq '';
189 return $a if $b eq 'old' || $b eq '';;
190 return $a le $b ? $a : $b;
191 }
192
193 sub read_config () {
194 if (open C, "$config") {
195 while (<C>) {
196 chomp; s/\s+$//; s/^\s+//;
197 if (m/^default\-pref\s+([-+][$list_fields]+)\s+([$search_opts])$/) {
198 $def_pref_list= $1;
199 $def_pref_search= $2;
200 } elsif (m/^hostname\s+(\S+)$/) {
201 $hostname= $1;
202 } elsif (m/^prefs\-file\s+(\S.*)$/) {
203 $peruser= $1;
204 } elsif (m/^services\-file\s+(\S.*)$/) {
205 $services= $1;
206 } elsif (m/\S/ && !m/^\#/) {
207 die;
208 }
209 }
210 close C or die $!;
211 } elsif ($! != &ENOENT) {
212 die $!;
213 }
214
215 if (!defined $hostname) {
216 chomp($hostname= `hostname -f`);
217 length $hostname or die $?;
218 }
219 }
220
221 sub read_services () {
222 if (open C, "$services") {
223 while (<C>) {
224 chomp; s/\s+$//; s/^\s+//;
225 next if m/^\#/ || !m/\S/;
226 if (m/^service\s+(\S.*)$/) {
227 $sname= $1;
228 die if exists $services{$sname};
229 } elsif (m/^(desc|command|verbose)\s+(\S.*)$/) {
230 die if exists $services{$sname}->{$1};
231 $services{$sname}->{$1}= $2;
232 } else {
233 die;
234 }
235 }
236 close C;
237 foreach $sname (keys %services) {
238 die unless exists $services{$sname}->{'command'};
239 }
240 } elsif ($! != &ENOENT) {
241 die $!;
242 }
243 }
244
245 sub read_per_user () {
246 if (open DL, "$peruser") {
247 while (<DL>) {
248 m/^(\w+) ([-+][$list_fields]+) ([$search_opts])$/ or die;
249 $user_pref_list{$1}= $2;
250 $user_pref_search{$1}= $3;
251 }
252 close DL;
253 } elsif ($! != &ENOENT) {
254 die $!;
255 }
256 }