1. added $actiondata to filter line to allow per action data such as no of hops
[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 DB_File;
15 use Fcntl;
16 use Carp;
17
18 use strict;
19 use vars qw(%u $dbm $filename %valid);
20
21 %u = ();
22 $dbm = undef;
23 $filename = undef;
24
25 # hash of valid elements and a simple prompt
26 %valid = (
27                   call => '0,Callsign',
28                   alias => '0,Real Callsign',
29                   name => '0,Name',
30                   qth => '0,Home QTH',
31                   lat => '0,Latitude,slat',
32                   long => '0,Longitude,slong',
33                   qra => '0,Locator',
34                   email => '0,E-mail Address',
35                   priv => '9,Privilege Level',
36                   lastin => '0,Last Time in,cldatetime',
37                   passwd => '9,Password',
38                   addr => '0,Full Address',
39                   'sort' => '0,Type of User', # A - ak1a, U - User, S - spider cluster, B - BBS
40                   xpert => '0,Expert Status,yesno',
41                   bbs => '0,Home BBS',
42                   node => '0,Last Node',
43                   homenode => '0,Home Node',
44                   lockout => '9,Locked out?,yesno',     # won't let them in at all
45                   dxok => '9,DX Spots?,yesno', # accept his dx spots?
46                   annok => '9,Announces?,yesno', # accept his announces?
47                   reg => '0,Registered?,yesno', # is this user registered?
48                   lang => '0,Language',
49                   hmsgno => '0,Highest Msgno',
50                   group => '0,Access Group,parray',     # used to create a group of users/nodes for some purpose or other
51                   isolate => '9,Isolate network,yesno',
52                  );
53
54 no strict;
55 sub AUTOLOAD
56 {
57         my $self = shift;
58         my $name = $AUTOLOAD;
59   
60         return if $name =~ /::DESTROY$/;
61         $name =~ s/.*:://o;
62   
63         confess "Non-existant field '$AUTOLOAD'" if !$valid{$name};
64         if (@_) {
65                 $self->{$name} = shift;
66                 #       $self->put();
67         }
68         return $self->{$name};
69 }
70
71 #
72 # initialise the system
73 #
74 sub init
75 {
76         my ($pkg, $fn, $mode) = @_;
77   
78         confess "need a filename in User" if !$fn;
79         $fn .= ".v2";
80         if ($mode) {
81                 $dbm = tie (%u, 'DB_File', $fn, O_CREAT|O_RDWR, 0666, $DB_BTREE) or confess "can't open user file: $fn ($!)";
82         } else {
83                 $dbm = tie (%u, 'DB_File', $fn, O_RDONLY, 0666, $DB_BTREE) or confess "can't open user file: $fn ($!)";
84         }
85         
86         $filename = $fn;
87 }
88
89 use strict;
90
91 #
92 # close the system
93 #
94
95 sub finish
96 {
97         untie %u;
98 }
99
100 #
101 # new - create a new user
102 #
103
104 sub new
105 {
106         my $pkg = shift;
107         my $call = uc shift;
108         #  $call =~ s/-\d+$//o;
109   
110         confess "can't create existing call $call in User\n!" if $u{$call};
111
112         my $self = bless {}, $pkg;
113         $self->{call} = $call;
114         $self->{'sort'} = 'U';
115         $self->{dxok} = 1;
116         $self->{annok} = 1;
117         $self->{lang} = $main::lang;
118         $u{call} = $self->encode();
119         return $self;
120 }
121
122 #
123 # get - get an existing user - this seems to return a different reference everytime it is
124 #       called - see below
125 #
126
127 sub get
128 {
129         my $pkg = shift;
130         my $call = uc shift;
131         #  $call =~ s/-\d+$//o;       # strip ssid
132         my $s = $u{$call};
133         return $s ?  decode($s) : undef;
134 }
135
136 #
137 # get all callsigns in the database 
138 #
139
140 sub get_all_calls
141 {
142         return (sort keys %u);
143 }
144
145 #
146 # get an existing either from the channel (if there is one) or from the database
147 #
148 # It is important to note that if you have done a get (for the channel say) and you
149 # want access or modify that you must use this call (and you must NOT use get's all
150 # over the place willy nilly!)
151 #
152
153 sub get_current
154 {
155         my $pkg = shift;
156         my $call = uc shift;
157         #  $call =~ s/-\d+$//o;       # strip ssid
158   
159         my $dxchan = DXChannel->get($call);
160         return $dxchan->user if $dxchan;
161         my $s = $u{$call};
162         return $s ? decode($s) : undef;
163 }
164
165 #
166 # put - put a user
167 #
168
169 sub put
170 {
171         my $self = shift;
172         my $call = $self->{call};
173         $u{$call} = $self->encode();
174 }
175
176
177 # create a string from a user reference
178 #
179 sub encode
180 {
181         my $self = shift;
182         my $out;
183         my $f;
184
185         $out = "bless( { ";
186         for $f (sort keys %$self) {
187                 my $val = $$self{$f};
188             if (ref $val) {          # it's an array (we think)
189                         $out .= "'$f'=>[ ";
190                         foreach (@$val) {
191                                 my $s = $_;
192                                 $out .= "'$s',";
193                         }
194                         $out .= " ],";
195             } else {
196                         $val =~ s/'/\\'/og;
197                         $val =~ s/\@/\\@/og;
198                         $out .= "'$f'=>q{$val},";
199                 }
200         }
201         $out .= " }, 'DXUser')";
202         return $out;
203 }
204
205 #
206 # create a hash from a string
207 #
208 sub decode
209 {
210         my $s = shift;
211         my $ref;
212         $s = '$ref = ' . $s;
213         eval $s;
214         confess $@ 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 1;
327 __END__