package TTXInventory; # # This module is a part of Trouble Ticket Express package # http://www.troubleticketexpress.com # # COPYRIGHT: 2006, United Web Coders # http://www.unitedwebcoders.com # # $Revision: 257 $ # $Date: 2006-08-16 05:47:08 -0400 (Wed, 16 Aug 2006) $ # $TTXInventory::VERSION='2.22'; BEGIN { $TTXInventory::REVISION = '$Revision: 257 $'; if ($TTXInventory::REVISION =~ /(\d+)/) { $TTXInventory::REVISION = $1; } }; use strict; use TTXData; my $idb = undef; my $states = undef; my $lasterror; my @itemfields = ('id', 'title', 'status', 'img'); my @statefields = ('id', 'title', 'img'); # ====================================================================== notesfn sub notesfn { my $cfg = TTXData::get('CONFIG'); my $dn = $cfg->get('basedir').'/inventory'; return "$dn/$_[0].cgi"; } # ======================================================================== idbfn sub idbfn { my $cfg = TTXData::get('CONFIG'); my $dn = $cfg->get('basedir').'/inventory'; my $fn = "$dn/index.cgi"; if (! -d $dn) { if (!mkdir($dn, 0777)) { $lasterror = "Failed to create inventory database directory"; return undef; } } if (! -f $fn) { open(IDB, ">$fn"); close(IDB); if (! -f $fn) { $lasterror = "Failed to create inventory database"; return undef; } } return $fn; } # ==================================================================== line2item sub line2item { chomp($_[0]); my @fields = split(/\|/, $_[0]); my %item; foreach my $key (@itemfields) { $item{$key} = shift @fields; $item{key} =~ s/^\s+//; $item{key} =~ s/\s+$//; } return %item; } # ==================================================================== item2line sub item2line { my $item = $_[0]; my @vals; foreach my $key (@itemfields) { my $val = $item->{$key}; $val =~ s/\|/!/g; push @vals, $val; } return join('|', @vals); } # ========================================================================= load sub load { if ($idb eq undef) { my $fn = idbfn(); return 0 if $fn eq undef; lockdb(); if (!open(IDB, $fn)) { $lasterror = "Failed to open inventory database file"; return 0; } flock(IDB,2); for (my $line = ; $line ne undef; $line = ) { my %item = line2item($line); next if $item{id} !~ /^\d+$/; my $nfn = notesfn($item{id}); if (-f $nfn) { if (open(NOTES, $nfn)) { $item{notes} = join('', ); close(NOTES); } } $idb->{$item{id}} = \%item; } close(IDB); unlockdb(); } return 1; } # ========================================================================= list sub list { return keys %{$idb} if load(); my @empty; return @empty; } # ====================================================================== getitem sub getitem { return undef if !load(); if (! exists $idb->{$_[0]}) { $lasterror = "Item $_[0] does not exist"; return undef; } return $idb->{$_[0]}; } # ======================================================================= savedb sub savedb { return 1 if $idb eq undef; my $fn = idbfn(); return 0 if $fn eq undef; return 0 if !lockdb(); if (!open(IDB, ">$fn")) { $lasterror = "Failed to open inventory database file"; unlockdb(); return 0; } flock(IDB,2); foreach my $id (sort {$a <=> $b} keys %{$idb}) { next if $id !~ /^\d+$/; print IDB item2line($idb->{$id})."\n"; my $nfn = notesfn($id); if ($idb->{$id}->{notes} ne undef) { if (open(NOTES, ">$nfn")) { print NOTES $idb->{$id}->{notes}; close(NOTES); } } elsif (-f $nfn) { unlink $nfn; } } close(IDB); unlockdb(); if (TTXData::get('_USECACHE')) { eval "use TTXCache"; TTXCache::purge() if $@ eq undef; } return 1; } # ========================================================================== add sub add { my $item = $_[0]; my $fn = idbfn(); return undef if $fn eq undef; return undef if !lockdb(); if (!load()) { unlockdb(); return undef; } my @lst = sort {$a <=> $b } list(); my $cnt = int(@lst); if (!$cnt) { $item->{id} = 1; } else { $item->{id} = int($lst[$cnt - 1]) + 1; } if (!open(IDB, ">>$fn")) { $lasterror = "Failed to open inventory database file"; unlockdb(); return undef; } flock(IDB,2); seek(IDB,0,2); print IDB item2line($item)."\n"; close(IDB); if ($item->{notes} ne undef) { my $nfn = notesfn($item->{id}); if (open(NOTES, ">$nfn")) { print NOTES $item->{notes}; close(NOTES); } } unlockdb(); if (TTXData::get('_USECACHE')) { eval "use TTXCache"; TTXCache::purge() if $@ eq undef; } $idb->{$item->{id}} = $item; return $item->{id}; } # ======================================================================= lockdb my $_lockcnt = 0; sub lockdb { if ($_lockcnt) { ++$_lockcnt; return 1; } my $lockfile = TTXData::get('CONFIG')->get('basedir')."/lockidb.ttx"; if (! -f $lockfile) { if (!open(LOCK, ">$lockfile")) { $lasterror = 'LOCKWRERR'; return 0; } } elsif (!open(LOCK,"+<$lockfile")) { $lasterror = 'LOCKOPNERR'; return 0; } flock(LOCK, 2); $_lockcnt = 1; return 1; } # ===================================================================== unlockdb sub unlockdb { return if !$_lockcnt; --$_lockcnt; if (!$_lockcnt) { flock(LOCK, 8); close LOCK; } } # ========================================================================== del sub del { my $id = $_[0]; return 0 if !lockdb(); if (!load()) { unlockdb(); return 0; } if (!exists $idb->{$id}) { unlockdb(); return 1; } my $nfn = notesfn($id); unlink $nfn if -f $nfn; delete $idb->{$id}; my $ccode = 1; if ($_lockcnt == 1) { $ccode = savedb(); } unlockdb(); return $ccode; } # ======================================================================== sdbfn sub sdbfn { my $cfg = TTXData::get('CONFIG'); my $dn = $cfg->get('basedir').'/inventory'; my $fn = "$dn/states.cgi"; if (! -d $dn) { if (!mkdir($dn, 0777)) { $lasterror = "Failed to create inventory database directory"; return undef; } } if (! -f $fn) { open(IDB, ">$fn"); close(IDB); if (! -f $fn) { $lasterror = "Failed to create status database"; return undef; } } return $fn; } # =================================================================== line2state sub line2state { chomp($_[0]); my @fields = split(/\|/, $_[0]); my %state; foreach my $key (@statefields) { $state{$key} = shift @fields; $state{key} =~ s/^\s+//; $state{key} =~ s/\s+$//; } return %state; } # =================================================================== state2line sub state2line { my $state = $_[0]; my @vals; foreach my $key (@statefields) { my $val = $state->{$key}; $val =~ s/\|/!/g; push @vals, $val; } return join('|', @vals); } # =================================================================== loadstates sub loadstates { if ($states eq undef) { $states = {}; my $fn = sdbfn(); return undef if $fn eq undef; if (!open(SDB, $fn)) { $lasterror = "Failed to open status database file"; return undef; } flock(SDB,2); for (my $line = ; $line ne undef; $line = ) { my %state = line2state($line); next if $state{id} !~ /^\d+$/; $states->{$state{id}} = \%state; } close(SDB); } return $states; } # ===================================================================== addstate sub addstate { my $state = $_[0]; my $fn = sdbfn(); return undef if $fn eq undef; return undef if !lockdb(); if (loadstates() eq undef) { unlockdb(); return undef; } my @lst = sort {$a <=> $b } keys %{$states}; my $cnt = int(@lst); if (!$cnt) { $state->{id} = 1; } else { $state->{id} = int($lst[$cnt - 1]) + 1; } if (!open(SDB, ">>$fn")) { $lasterror = "Failed to open status database file"; unlockdb(); return undef; } flock(SDB,2); seek(SDB,0,2); print SDB state2line($state)."\n"; close(SDB); unlockdb(); $states->{$state->{id}} = $state; return $state->{id}; } # =================================================================== savestates sub savestates { return 1 if $states eq undef; my $fn = sdbfn(); return 0 if $fn eq undef; return 0 if !lockdb(); if (!open(SDB, ">$fn")) { $lasterror = "Failed to open status database file"; unlockdb(); return 0; } flock(SDB,2); foreach my $id (sort {$a <=> $b} keys %{$states}) { next if $id !~ /^\d+$/; print SDB state2line($states->{$id})."\n"; } close(SDB); unlockdb(); return 1; } # ======================================================================== error sub error { return $lasterror; } 1; #