3 # Database Handler module for DXSpider
5 # Copyright (c) 1999 Dirk Koopman G1TLH
17 use vars qw($opentime $dbbase %avail %valid $lastprocesstime $nextstream %stream);
19 $opentime = 5*60; # length of time a database stays open after last access
20 $dbbase = "$main::root/db"; # where all the databases are kept;
21 %avail = (); # The hash contains a list of all the databases
23 accesst => '9,Last Accs Time,atime',
24 createt => '9,Create Time,atime',
25 lastt => '9,Last Upd Time,atime',
27 db => '9,DB Tied hash',
28 remote => '0,Remote Database',
29 pre => '0,Heading txt',
31 chain => '0,Search these,parray',
32 disable => '0,Disabled?,yesno',
33 nf => '0,Not Found txt',
34 cal => '0,No Key txt',
35 allowread => '9,Allowed read,parray',
36 denyread => '9,Deny read,parray',
37 allowupd => '9,Allow upd,parray',
38 denyupd => '9,Deny upd,parray',
39 fwdupd => '9,Forw upd to,parray',
40 template => '9,Upd Templates,parray',
41 te => '9,End Upd txt',
42 tae => '9,End App txt',
43 atemplate => '9,App Templates,parray',
44 help => '0,Help txt,parray',
45 localcmd => '0,Local Command',
48 $lastprocesstime = time;
52 use vars qw($VERSION $BRANCH);
54 main::mkver($VERSION = q$Revision$);
56 # allocate a new stream for this request
60 my $n = ++$nextstream;
61 $stream{$n} = { n=>$n, call=>$call, t=>$main::systime };
79 # load all the database descriptors
82 my $s = readfilestr($dbbase, "dbs", "pl");
87 %avail = ( %$a ) if ref $a;
91 # save all the database descriptors
95 writefilestr($dbbase, "dbs", "pl", \%avail);
98 # get the descriptor of the database you want.
101 return undef unless %avail;
104 my $r = $avail{$name};
106 # search for a partial if not found direct
108 for (sort { $a->{name} cmp $b->{name} }values %avail) {
109 if ($_->{name} =~ /^$name/) {
122 $self->{accesst} = $main::systime;
123 return $self->{db} if $self->{db};
125 $self->{db} = tie %hash, 'DB_File', "$dbbase/$self->{name}";
144 for (values %avail) {
150 # get a value from the database
158 $key =~ s/[\@\$\&\%\*]+//g;
159 $key =~ s/^[\.\/]+//g;
161 # make sure we are open
163 if ($self->{localcmd}) {
164 my $dxchan = $main::me;
165 $dxchan->{remotecmd} = 1; # for the benefit of any command that needs to know
166 my $oldpriv = $dxchan->{priv};
168 my @in = (DXCommandmode::run_cmd($dxchan, "$self->{localcmd} $key"));
169 $dxchan->{priv} = $oldpriv;
170 delete $dxchan->{remotecmd};
171 return @in ? join("\n", @in) : undef;
172 } elsif ($self->{db}) {
173 my $s = $self->{db}->get($key, $value);
174 return $s ? undef : $value;
179 # put a value to the database
186 # make sure we are open
189 my $s = $self->{db}->put($key, $value);
190 return $s ? undef : 1;
195 # create a new database params: <name> [<remote node call>]
204 $self->{name} = lc $name;
205 $self->{remote} = uc $remote if $remote;
206 $self->{chain} = $chain if $chain && ref $chain;
207 $self->{accesst} = $self->{createt} = $self->{lastt} = $main::systime;
208 $self->{localcmd} = lc $cmd if $cmd;
210 $avail{$self->{name}} = $self;
211 mkdir $dbbase, 02775 unless -e $dbbase;
221 unlink "$dbbase/$self->{name}";
222 delete $avail{$self->{name}};
227 # process intermediate lines for an update
228 # NOTE THAT THIS WILL BE CALLED FROM DXCommandmode and the
229 # object will be a DXChannel (actually DXCommandmode)
237 # periodic maintenance
239 # just close any things that haven't been accessed for the default
245 if ($main::systime - $lastprocesstime >= 60) {
247 for (values %avail) {
248 if ($main::systime - $_->{accesst} > $opentime) {
253 $lastprocesstime = $main::systime;
266 # incoming DB Request
267 my @in = DXCommandmode::run_cmd($self, "dbshow $_[4] $_[5]");
268 sendremote($self, $_[2], $_[3], @in);
275 # incoming DB Information
276 my $n = getstream($_[3]);
278 my $mchan = DXChannel::get($n->{call});
279 $mchan->send($_[2] . ":$_[4]") if $mchan;
287 # incoming DB Complete
299 # send back a trache of data to the remote
300 # remember $dxchan is a dxchannel
308 $dxchan->send(DXProt::pc45($main::mycall, $tonode, $stream, $_));
310 $dxchan->send(DXProt::pc46($main::mycall, $tonode, $stream));
313 # print a value from the db reference
318 return $self->{$s} ? $self->{$s} : undef;
321 # various access routines
324 # return a list of valid elements
333 # return a prompt for a field
338 my ($self, $ele) = @_;
346 my $name = $AUTOLOAD;
347 return if $name =~ /::DESTROY$/;
350 confess "Non-existant field '$AUTOLOAD'" if !$valid{$name};
351 # this clever line of code creates a subroutine which takes over from autoload
352 # from OO Perl - Conway
353 *$AUTOLOAD = sub {@_ > 1 ? $_[0]->{$name} = $_[1] : $_[0]->{$name}};