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',
47 $lastprocesstime = time;
51 use vars qw($VERSION $BRANCH);
52 $VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
53 $BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /\d+\.\d+\.(\d+)\.(\d+)/ || (0,0));
54 $main::build += $VERSION;
55 $main::branch += $BRANCH;
57 # allocate a new stream for this request
61 my $n = ++$nextstream;
62 $stream{$n} = { n=>$n, call=>$call, t=>$main::systime };
80 # load all the database descriptors
83 my $s = readfilestr($dbbase, "dbs", "pl");
88 %avail = ( %$a ) if ref $a;
92 # save all the database descriptors
96 writefilestr($dbbase, "dbs", "pl", \%avail);
99 # get the descriptor of the database you want.
102 return undef unless %avail;
105 my $r = $avail{$name};
107 # search for a partial if not found direct
109 for (sort { $a->{name} cmp $b->{name} }values %avail) {
110 if ($_->{name} =~ /^$name/) {
123 $self->{accesst} = $main::systime;
124 return $self->{db} if $self->{db};
126 $self->{db} = tie %hash, 'DB_File', "$dbbase/$self->{name}";
145 for (values %avail) {
151 # get a value from the database
158 # make sure we are open
161 my $s = $self->{db}->get($key, $value);
162 return $s ? undef : $value;
167 # put a value to the database
174 # make sure we are open
177 my $s = $self->{db}->put($key, $value);
178 return $s ? undef : 1;
183 # create a new database params: <name> [<remote node call>]
190 $self->{name} = lc $name;
191 $self->{remote} = uc $remote if $remote;
192 $self->{chain} = $chain if $chain && ref $chain;
193 $self->{accesst} = $self->{createt} = $self->{lastt} = $main::systime;
194 $avail{$self->{name}} = $self;
195 mkdir $dbbase, 02775 unless -e $dbbase;
205 unlink "$dbbase/$self->{name}";
206 delete $avail{$self->{name}};
211 # process intermediate lines for an update
212 # NOTE THAT THIS WILL BE CALLED FROM DXCommandmode and the
213 # object will be a DXChannel (actually DXCommandmode)
221 # periodic maintenance
223 # just close any things that haven't been accessed for the default
229 my ($dxchan, $line) = @_;
231 # this is periodic processing
232 if (!$dxchan || !$line) {
233 if ($main::systime - $lastprocesstime >= 60) {
235 for (values %avail) {
236 if ($main::systime - $_->{accesst} > $opentime) {
241 $lastprocesstime = $main::systime;
246 my @f = split /\^/, $line;
247 my ($pcno) = $f[0] =~ /^PC(\d\d)/; # just get the number
249 # route out ones that are not for us
250 if ($f[1] eq $main::mycall) {
253 $dxchan->route($f[1], $line);
258 if ($pcno == 37) { # probably obsolete
262 if ($pcno == 44) { # incoming DB Request
263 my $db = getdesc($f[4]);
266 sendremote($dxchan, $f[2], $f[3], $dxchan->msg('db1', $db->{remote}));
268 my $value = $db->getkey($f[5]);
270 my @out = split /\n/, $value;
271 sendremote($dxchan, $f[2], $f[3], @out);
273 sendremote($dxchan, $f[2], $f[3], $dxchan->msg('db2', $f[5], $db->{name}));
277 sendremote($dxchan, $f[2], $f[3], $dxchan->msg('db3', $f[4]));
282 if ($pcno == 45) { # incoming DB Information
283 my $n = getstream($f[3]);
285 my $mchan = DXChannel->get($n->{call});
286 $mchan->send($f[2] . ":$f[4]") if $mchan;
291 if ($pcno == 46) { # incoming DB Complete
296 if ($pcno == 47) { # incoming DB Update request
300 if ($pcno == 48) { # incoming DB Update request
306 # send back a trache of data to the remote
307 # remember $dxchan is a dxchannel
315 $dxchan->send(DXProt::pc45($main::mycall, $tonode, $stream, $_));
317 $dxchan->send(DXProt::pc46($main::mycall, $tonode, $stream));
320 # print a value from the db reference
325 return $self->{$s} ? $self->{$s} : undef;
328 # various access routines
331 # return a list of valid elements
340 # return a prompt for a field
345 my ($self, $ele) = @_;
353 my $name = $AUTOLOAD;
354 return if $name =~ /::DESTROY$/;
357 confess "Non-existant field '$AUTOLOAD'" if !$valid{$name};
358 # this clever line of code creates a subroutine which takes over from autoload
359 # from OO Perl - Conway
360 *$AUTOLOAD = sub {@_ > 1 ? $_[0]->{$name} = $_[1] : $_[0]->{$name}};