# $Id: Text.pm,v 1.2 2003/01/16 19:41:31 lstein Exp $
package HTTPD::GroupAdmin::Text;
use Carp ();
use strict;
use vars qw(@ISA $DLM $VERSION $LineMax);
@ISA = qw(HTTPD::GroupAdmin);
$VERSION = (qw$Revision: 1.2 $)[1];
$DLM = ": ";
# Maximum size of each line in the group file. Anytime we have more
# group data than this we split it up into multiple lines. At least
# Apache 1.3.4 this limitation on lines in the group file.
$LineMax = 8 * 1024;
my %Default = (PATH => ".",
DB => ".htgroup",
FLAGS => "rwc",
);
sub new {
my($class) = shift;
my $self = bless { %Default, @_ } => $class;
#load the DBM methods
$self->load("HTTPD::GroupAdmin::DBM");
$self->db($self->{DB});
return $self;
}
sub _tie {
my($self) = @_;
my($fh,$db) = ($self->gensym(), $self->{DB});
my($key,$val);
printf STDERR "%s->_tie($db)\n", $self->class if $self->debug;
$db =~ /^([^<>;|]+)$/ or Carp::croak("Bad file name '$db'"); $db = $1; #untaint
open($fh, $db) or return; #must be new
while(<$fh>) {
($key,$val) = $self->_parseline($fh, $_);
next unless $key =~ /\S/;
$self->{'_HASH'}{$key} = (exists $self->{'_HASH'}{$key} ?
join(" ", $self->{'_HASH'}{$key}, $val) :
$val);
}
CORE::close $fh;
}
sub _untie {
my($self) = @_;
return unless exists $self->{'_HASH'};
$self->commit;
delete $self->{'_HASH'};
}
DESTROY {
$_[0]->_untie('_HASH');
$_[0]->unlock;
}
sub commit {
my($self) = @_;
return if $self->readonly;
my($fh,$db) = ($self->gensym(), $self->{DB});
my($key,$val);
$db =~ /^([^<>;|]+)$/ or return (0, "Bad file name '$db'"); $db = $1;
#untaint
my $tmp_db = "$db.$$"; # Use temp file until write is complete.
open($fh, ">$tmp_db") or return (0, "open: '$tmp_db' $!");
while(($key,$val) = each %{$self->{'_HASH'}}) {
print $fh $self->_formatline($key,$val)
or return (0, "print: '$tmp_db' failed: $!");
}
CORE::close $fh
or return (0, "close: '$tmp_db' failed: $!");
my $mode = (stat $db)[2];
chmod $mode, $tmp_db if $mode;
rename( $tmp_db,$db )
or return (0, "rename '$tmp_db' to '$db' failed: $!");
1;
}
sub _parseline {
my($self,$fh) = (shift,shift);
local $_ = shift;
chomp; s/^\s+//; s/\s+$//;
my($key, $val) = split(/:\s*/, $_, 2);
$val =~ s/\s* \s*/ /g;
return ($key,$val);
}
sub _formatline {
my($self,$key,$val) = @_;
my( $FieldMax ) = $LineMax - length( $key );
my( @fields );
$val =~ s/(\w) /$1 /g;
while( length( $val ) > $FieldMax ) {
my( $tail, $field );
$field = substr( $val, 0, $FieldMax );
$val = substr( $val, $FieldMax );
( $field, $tail ) = ( $field =~ m/^(.+) (\S+ ?)$/ );
$val = $tail . $val;
push( @fields, $field );
}
map( join($DLM, $key,$_) . "\n", @fields, $val );
}
sub add {
my $self = shift;
return(0, $self->db . " is read-only!") if $self->readonly;
$self->HTTPD::GroupAdmin::DBM::add(@_);
}
package HTTPD::GroupAdmin::Text::_generic;
use vars qw(@ISA);
@ISA = qw(HTTPD::GroupAdmin::Text
HTTPD::GroupAdmin::DBM);
1;
__END__