get set/nobeeps to work?
[spider.git] / perl / DXUser.pm
1 #
2 # DX cluster user routines
3 #
4 # Copyright (c) 1998 - Dirk Koopman G1TLH
5 #
6 # $Id$
7 #
8
9 package DXUser;
10
11 require Exporter;
12 @ISA = qw(Exporter);
13
14 use DXLog;
15 use DB_File;
16 use Data::Dumper;
17 use Fcntl;
18 use Carp;
19
20 use strict;
21 use vars qw(%u $dbm $filename %valid);
22
23 %u = ();
24 $dbm = undef;
25 $filename = undef;
26
27 # hash of valid elements and a simple prompt
28 %valid = (
29                   call => '0,Callsign',
30                   alias => '0,Real Callsign',
31                   name => '0,Name',
32                   qth => '0,Home QTH',
33                   lat => '0,Latitude,slat',
34                   long => '0,Longitude,slong',
35                   qra => '0,Locator',
36                   email => '0,E-mail Address',
37                   priv => '9,Privilege Level',
38                   lastin => '0,Last Time in,cldatetime',
39                   passwd => '9,Password',
40                   addr => '0,Full Address',
41                   'sort' => '0,Type of User', # A - ak1a, U - User, S - spider cluster, B - BBS
42                   xpert => '0,Expert Status,yesno',
43                   bbs => '0,Home BBS',
44                   node => '0,Last Node',
45                   homenode => '0,Home Node',
46                   lockout => '9,Locked out?,yesno',     # won't let them in at all
47                   dxok => '9,DX Spots?,yesno', # accept his dx spots?
48                   annok => '9,Announces?,yesno', # accept his announces?
49                   reg => '0,Registered?,yesno', # is this user registered?
50                   lang => '0,Language',
51                   hmsgno => '0,Highest Msgno',
52                   group => '0,Access Group,parray',     # used to create a group of users/nodes for some purpose or other
53                   isolate => '9,Isolate network,yesno',
54                   wantbeep => '0,Rec Beep,yesno',
55                   wantann => '0,Rec Announce,yesno',
56                   wantwwv => '0,Rec WWV,yesno',
57                   wanttalk => '0,Rec Talk,yesno',
58                   wantwx => '0,Rec WX,yesno',
59                   wantdx => '0,Rec DX Spots,yesno',
60                   pingint => '9,Node Ping interval',
61                   nopings => '9,Ping Obs Count',
62                   wantlogininfo => '9,Login info req,yesno',
63                  );
64
65 no strict;
66 sub AUTOLOAD
67 {
68         my $self = shift;
69         my $name = $AUTOLOAD;
70   
71         return if $name =~ /::DESTROY$/;
72         $name =~ s/.*:://o;
73   
74         confess "Non-existant field '$AUTOLOAD'" if !$valid{$name};
75         if (@_) {
76                 $self->{$name} = shift;
77         }
78         return $self->{$name};
79 }
80
81 #
82 # initialise the system
83 #
84 sub init
85 {
86         my ($pkg, $fn, $mode) = @_;
87   
88         confess "need a filename in User" if !$fn;
89         $fn .= ".v2";
90         if ($mode) {
91                 $dbm = tie (%u, 'DB_File', $fn, O_CREAT|O_RDWR, 0666, $DB_BTREE) or confess "can't open user file: $fn ($!)";
92         } else {
93                 $dbm = tie (%u, 'DB_File', $fn, O_RDONLY, 0666, $DB_BTREE) or confess "can't open user file: $fn ($!)";
94         }
95         
96         $filename = $fn;
97 }
98
99 use strict;
100
101 #
102 # close the system
103 #
104
105 sub finish
106 {
107         undef $dbm;
108         untie %u;
109 }
110
111 #
112 # new - create a new user
113 #
114
115 sub new
116 {
117         my $pkg = shift;
118         my $call = uc shift;
119         #  $call =~ s/-\d+$//o;
120   
121 #       confess "can't create existing call $call in User\n!" if $u{$call};
122
123         my $self = bless {}, $pkg;
124         $self->{call} = $call;
125         $self->{'sort'} = 'U';
126         $self->{dxok} = 1;
127         $self->{annok} = 1;
128         $self->{lang} = $main::lang;
129         $self->put;
130         return $self;
131 }
132
133 #
134 # get - get an existing user - this seems to return a different reference everytime it is
135 #       called - see below
136 #
137
138 sub get
139 {
140         my $pkg = shift;
141         my $call = uc shift;
142         #  $call =~ s/-\d+$//o;       # strip ssid
143         my $s = $u{$call};
144         return $s ?  decode($s) : undef;
145 }
146
147 #
148 # get all callsigns in the database 
149 #
150
151 sub get_all_calls
152 {
153         return (sort keys %u);
154 }
155
156 #
157 # get an existing either from the channel (if there is one) or from the database
158 #
159 # It is important to note that if you have done a get (for the channel say) and you
160 # want access or modify that you must use this call (and you must NOT use get's all
161 # over the place willy nilly!)
162 #
163
164 sub get_current
165 {
166         my $pkg = shift;
167         my $call = uc shift;
168         #  $call =~ s/-\d+$//o;       # strip ssid
169   
170         my $dxchan = DXChannel->get($call);
171         return $dxchan->user if $dxchan;
172         my $s = $u{$call};
173         return $s ? decode($s) : undef;
174 }
175
176 #
177 # put - put a user
178 #
179
180 sub put
181 {
182         my $self = shift;
183         confess "Trying to put nothing!" unless $self && ref $self;
184         my $call = $self->{call};
185         $u{$call} = $self->encode();
186 }
187
188
189 # create a string from a user reference
190 #
191 sub encode
192 {
193         my $self = shift;
194         my $dd = new Data::Dumper([$self]);
195         $dd->Indent(0);
196         $dd->Terse(1);
197     $dd->Quotekeys($] < 5.005 ? 1 : 0);
198         return $dd->Dumpxs;
199 }
200
201 #
202 # create a hash from a string
203 #
204 sub decode
205 {
206         my $s = shift;
207         my $ref;
208         $s = '$ref = ' . $s;
209         eval $s;
210         Log('DXUser', $@) if $@;
211         $ref = undef if $@;
212         return $ref;
213 }
214
215 #
216 # del - delete a user
217 #
218
219 sub del
220 {
221         my $self = shift;
222         my $call = $self->{call};
223         delete $u{$call};
224 }
225
226 #
227 # close - close down a user
228 #
229
230 sub close
231 {
232         my $self = shift;
233         $self->{lastin} = time;
234         $self->put();
235 }
236
237 #
238 # return a list of valid elements 
239
240
241 sub fields
242 {
243         return keys(%valid);
244 }
245
246 #
247 # group handling
248 #
249
250 # add one or more groups
251 sub add_group
252 {
253         my $self = shift;
254         my $ref = $self->{group} || [ 'local' ];
255         $self->{group} = $ref if !$self->{group};
256         push @$ref, @_ if @_;
257 }
258
259 # remove one or more groups
260 sub del_group
261 {
262         my $self = shift;
263         my $ref = $self->{group} || [ 'local' ];
264         my @in = @_;
265         
266         $self->{group} = $ref if !$self->{group};
267         
268         @$ref = map { my $a = $_; return (grep { $_ eq $a } @in) ? () : $a } @$ref;
269 }
270
271 # does this thing contain all the groups listed?
272 sub union
273 {
274         my $self = shift;
275         my $ref = $self->{group};
276         my $n;
277         
278         return 0 if !$ref || @_ == 0;
279         return 1 if @$ref == 0 && @_ == 0;
280         for ($n = 0; $n < @_; ) {
281                 for (@$ref) {
282                         my $a = $_;
283                         $n++ if grep $_ eq $a, @_; 
284                 }
285         }
286         return $n >= @_;
287 }
288
289 # simplified group test just for one group
290 sub in_group
291 {
292         my $self = shift;
293         my $s = shift;
294         my $ref = $self->{group};
295         
296         return 0 if !$ref;
297         return grep $_ eq $s, $ref;
298 }
299
300 # set up a default group (only happens for them's that connect direct)
301 sub new_group
302 {
303         my $self = shift;
304         $self->{group} = [ 'local' ];
305 }
306
307 #
308 # return a prompt for a field
309 #
310
311 sub field_prompt
312
313         my ($self, $ele) = @_;
314         return $valid{$ele};
315 }
316
317 # some variable accessors
318 sub sort
319 {
320         my $self = shift;
321         @_ ? $self->{'sort'} = shift : $self->{'sort'} ;
322 }
323
324 # some accessors
325 sub _want
326 {
327         my $n = shift;
328         my $self = shift;
329         my $val = shift;
330         my $s = "want$n";
331         $self->{$n} = $val if $val;
332         return exists $self->{$n} ? $self->{$n} : 1;
333 }
334
335 sub wantbeep
336 {
337         return _want('beep', @_);
338 }
339
340 sub wantann
341 {
342         return _want('ann', @_);
343 }
344
345 sub wantwwv
346 {
347         return _want('wwv', @_);
348 }
349
350 sub wantwx
351 {
352         return _want('wx', @_);
353 }
354
355 sub wantdx
356 {
357         return _want('dx', @_);
358 }
359
360 sub wanttalk
361 {
362         return _want('talk', @_);
363 }
364
365 sub wantlogininfo
366 {
367         my $self = shift;
368         my $n = shift;
369         $self->{wantlogininfo} = $n if $n;
370         return exists $self->{wantlogininfo} ? $self->{wantlogininfo} : 0;
371 }
372
373 1;
374 __END__