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