removed more 5.004 ambiguities including making the format of data
[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                  );
62
63 no strict;
64 sub AUTOLOAD
65 {
66         my $self = shift;
67         my $name = $AUTOLOAD;
68   
69         return if $name =~ /::DESTROY$/;
70         $name =~ s/.*:://o;
71   
72         confess "Non-existant field '$AUTOLOAD'" if !$valid{$name};
73         if (@_) {
74                 $self->{$name} = shift;
75         }
76         return $self->{$name};
77 }
78
79 #
80 # initialise the system
81 #
82 sub init
83 {
84         my ($pkg, $fn, $mode) = @_;
85   
86         confess "need a filename in User" if !$fn;
87         $fn .= ".v2";
88         if ($mode) {
89                 $dbm = tie (%u, 'DB_File', $fn, O_CREAT|O_RDWR, 0666, $DB_BTREE) or confess "can't open user file: $fn ($!)";
90         } else {
91                 $dbm = tie (%u, 'DB_File', $fn, O_RDONLY, 0666, $DB_BTREE) or confess "can't open user file: $fn ($!)";
92         }
93         
94         $filename = $fn;
95 }
96
97 use strict;
98
99 #
100 # close the system
101 #
102
103 sub finish
104 {
105         undef $dbm;
106         untie %u;
107 }
108
109 #
110 # new - create a new user
111 #
112
113 sub new
114 {
115         my $pkg = shift;
116         my $call = uc shift;
117         #  $call =~ s/-\d+$//o;
118   
119 #       confess "can't create existing call $call in User\n!" if $u{$call};
120
121         my $self = bless {}, $pkg;
122         $self->{call} = $call;
123         $self->{'sort'} = 'U';
124         $self->{dxok} = 1;
125         $self->{annok} = 1;
126         $self->{lang} = $main::lang;
127         $self->put;
128         return $self;
129 }
130
131 #
132 # get - get an existing user - this seems to return a different reference everytime it is
133 #       called - see below
134 #
135
136 sub get
137 {
138         my $pkg = shift;
139         my $call = uc shift;
140         #  $call =~ s/-\d+$//o;       # strip ssid
141         my $s = $u{$call};
142         return $s ?  decode($s) : undef;
143 }
144
145 #
146 # get all callsigns in the database 
147 #
148
149 sub get_all_calls
150 {
151         return (sort keys %u);
152 }
153
154 #
155 # get an existing either from the channel (if there is one) or from the database
156 #
157 # It is important to note that if you have done a get (for the channel say) and you
158 # want access or modify that you must use this call (and you must NOT use get's all
159 # over the place willy nilly!)
160 #
161
162 sub get_current
163 {
164         my $pkg = shift;
165         my $call = uc shift;
166         #  $call =~ s/-\d+$//o;       # strip ssid
167   
168         my $dxchan = DXChannel->get($call);
169         return $dxchan->user if $dxchan;
170         my $s = $u{$call};
171         return $s ? decode($s) : undef;
172 }
173
174 #
175 # put - put a user
176 #
177
178 sub put
179 {
180         my $self = shift;
181         confess "Trying to put nothing!" unless $self && ref $self;
182         my $call = $self->{call};
183         $u{$call} = $self->encode();
184 }
185
186
187 # create a string from a user reference
188 #
189 sub encode
190 {
191         my $self = shift;
192         my $dd = new Data::Dumper([$self]);
193         $dd->Indent(0);
194         $dd->Terse(1);
195     $dd->Quotekeys($] < 5.005 ? 1 : 0);
196         return $dd->Dumpxs;
197 }
198
199 #
200 # create a hash from a string
201 #
202 sub decode
203 {
204         my $s = shift;
205         my $ref;
206         $s = '$ref = ' . $s;
207         eval $s;
208         Log('DXUser', $@) if $@;
209         $ref = undef if $@;
210         return $ref;
211 }
212
213 #
214 # del - delete a user
215 #
216
217 sub del
218 {
219         my $self = shift;
220         my $call = $self->{call};
221         delete $u{$call};
222 }
223
224 #
225 # close - close down a user
226 #
227
228 sub close
229 {
230         my $self = shift;
231         $self->{lastin} = time;
232         $self->put();
233 }
234
235 #
236 # return a list of valid elements 
237
238
239 sub fields
240 {
241         return keys(%valid);
242 }
243
244 #
245 # group handling
246 #
247
248 # add one or more groups
249 sub add_group
250 {
251         my $self = shift;
252         my $ref = $self->{group} || [ 'local' ];
253         $self->{group} = $ref if !$self->{group};
254         push @$ref, @_ if @_;
255 }
256
257 # remove one or more groups
258 sub del_group
259 {
260         my $self = shift;
261         my $ref = $self->{group} || [ 'local' ];
262         my @in = @_;
263         
264         $self->{group} = $ref if !$self->{group};
265         
266         @$ref = map { my $a = $_; return (grep { $_ eq $a } @in) ? () : $a } @$ref;
267 }
268
269 # does this thing contain all the groups listed?
270 sub union
271 {
272         my $self = shift;
273         my $ref = $self->{group};
274         my $n;
275         
276         return 0 if !$ref || @_ == 0;
277         return 1 if @$ref == 0 && @_ == 0;
278         for ($n = 0; $n < @_; ) {
279                 for (@$ref) {
280                         my $a = $_;
281                         $n++ if grep $_ eq $a, @_; 
282                 }
283         }
284         return $n >= @_;
285 }
286
287 # simplified group test just for one group
288 sub in_group
289 {
290         my $self = shift;
291         my $s = shift;
292         my $ref = $self->{group};
293         
294         return 0 if !$ref;
295         return grep $_ eq $s, $ref;
296 }
297
298 # set up a default group (only happens for them's that connect direct)
299 sub new_group
300 {
301         my $self = shift;
302         $self->{group} = [ 'local' ];
303 }
304
305 #
306 # return a prompt for a field
307 #
308
309 sub field_prompt
310
311         my ($self, $ele) = @_;
312         return $valid{$ele};
313 }
314
315 # some variable accessors
316 sub sort
317 {
318         my $self = shift;
319         @_ ? $self->{'sort'} = shift : $self->{'sort'} ;
320 }
321
322 # some accessors
323 sub _want
324 {
325         my $n = shift;
326         my $self = shift;
327         my $s = "want$n";
328         return $self->{$n} = shift if @_;
329         return defined $self->{$n} ? $self->{$n} : 1;
330 }
331
332 sub wantbeep
333 {
334         return _want('beep', @_);
335 }
336
337 sub wantann
338 {
339         return _want('ann', @_);
340 }
341
342 sub wantwwv
343 {
344         return _want('wwv', @_);
345 }
346
347 sub wantwx
348 {
349         return _want('wx', @_);
350 }
351
352 sub wantdx
353 {
354         return _want('dx', @_);
355 }
356
357 sub wanttalk
358 {
359         return _want('talk', @_);
360 }
361
362 1;
363 __END__