1. Incorporated sh/st, (un)set/lockout, forward/opername from Iain G0RDI
[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 MLDBM qw(DB_File);
15 use Fcntl;
16 use Carp;
17
18 use strict;
19 use vars qw(%u $dbm $filename %valid);
20
21 %u = undef;
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 );
52
53 no strict;
54 sub AUTOLOAD
55 {
56   my $self = shift;
57   my $name = $AUTOLOAD;
58   
59   return if $name =~ /::DESTROY$/;
60   $name =~ s/.*:://o;
61   
62   confess "Non-existant field '$AUTOLOAD'" if !$valid{$name};
63   if (@_) {
64     $self->{$name} = shift;
65         $self->put();
66   }
67   return $self->{$name};
68 }
69
70 #
71 # initialise the system
72 #
73 sub init
74 {
75   my ($pkg, $fn) = @_;
76   
77   confess "need a filename in User" if !$fn;
78   $dbm = tie (%u, MLDBM, $fn, O_CREAT|O_RDWR, 0666) or confess "can't open user file: $fn ($!)";
79   $filename = $fn;
80 }
81
82 use strict;
83
84 #
85 # close the system
86 #
87
88 sub finish
89 {
90   $dbm = undef;
91   untie %u;
92 }
93
94 #
95 # new - create a new user
96 #
97
98 sub new
99 {
100   my $pkg = shift;
101   my $call = uc shift;
102 #  $call =~ s/-\d+$//o;
103   
104   confess "can't create existing call $call in User\n!" if $u{$call};
105
106   my $self = {};
107   $self->{call} = $call;
108   $self->{sort} = 'U';
109   $self->{dxok} = 1;
110   $self->{annok} = 1;
111   $self->{lang} = $main::lang;
112   bless $self, $pkg;
113   $u{call} = $self;
114 }
115
116 #
117 # get - get an existing user - this seems to return a different reference everytime it is
118 #       called - see below
119 #
120
121 sub get
122 {
123   my $pkg = shift;
124   my $call = uc shift;
125 #  $call =~ s/-\d+$//o;       # strip ssid
126   return $u{$call};
127 }
128
129 #
130 # get all callsigns in the database 
131 #
132
133 sub get_all_calls
134 {
135   return (sort keys %u);
136 }
137
138 #
139 # get an existing either from the channel (if there is one) or from the database
140 #
141 # It is important to note that if you have done a get (for the channel say) and you
142 # want access or modify that you must use this call (and you must NOT use get's all
143 # over the place willy nilly!)
144 #
145
146 sub get_current
147 {
148   my $pkg = shift;
149   my $call = uc shift;
150 #  $call =~ s/-\d+$//o;       # strip ssid
151   
152   my $dxchan = DXChannel->get($call);
153   return $dxchan->user if $dxchan;
154   return $u{$call};
155 }
156
157 #
158 # put - put a user
159 #
160
161 sub put
162 {
163   my $self = shift;
164   my $call = $self->{call};
165   $u{$call} = $self;
166 }
167
168 #
169 # del - delete a user
170 #
171
172 sub del
173 {
174   my $self = shift;
175   my $call = $self->{call};
176   delete $u{$call};
177 }
178
179 #
180 # close - close down a user
181 #
182
183 sub close
184 {
185   my $self = shift;
186   $self->{lastin} = time;
187   $self->put();
188 }
189
190 #
191 # return a list of valid elements 
192
193
194 sub fields
195 {
196   return keys(%valid);
197 }
198
199 #
200 # group handling
201 #
202
203 # add one or more groups
204 sub add_group
205 {
206         my $self = shift;
207         my $ref = $self->{group} || [ 'local' ];
208         $self->{group} = $ref if !$self->{group};
209         push @$ref, @_ if @_;
210 }
211
212 # remove one or more groups
213 sub del_group
214 {
215         my $self = shift;
216         my $ref = $self->{group} || [ 'local' ];
217         my @in = @_;
218         
219         $self->{group} = $ref if !$self->{group};
220         
221         @$ref = map { my $a = $_; return (grep { $_ eq $a } @in) ? () : $a } @$ref;
222 }
223
224 # does this thing contain all the groups listed?
225 sub union
226 {
227         my $self = shift;
228         my $ref = $self->{group};
229         my $n;
230         
231         return 0 if !$ref || @_ == 0;
232         return 1 if @$ref == 0 && @_ == 0;
233         for ($n = 0; $n < @_; ) {
234                 for (@$ref) {
235                         my $a = $_;
236                         $n++ if grep $_ eq $a, @_; 
237                 }
238         }
239         return $n >= @_;
240 }
241
242 # simplified group test just for one group
243 sub in_group
244 {
245         my $self = shift;
246         my $s = shift;
247         my $ref = $self->{group};
248         
249         return 0 if !$ref;
250         return grep $_ eq $s, $ref;
251 }
252
253 # set up a default group (only happens for them's that connect direct)
254 sub new_group
255 {
256         my $self = shift;
257         $self->{group} = [ 'local' ];
258 }
259
260 #
261 # return a prompt for a field
262 #
263
264 sub field_prompt
265
266   my ($self, $ele) = @_;
267   return $valid{$ele};
268 }
269
270 # some variable accessors
271 sub sort
272 {
273   my $self = shift;
274   @_ ? $self->{sort} = shift : $self->{sort} ;
275 }
276 1;
277 __END__