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