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