gunnar: server/kolabconf/lib/Kolab Conf.pm,1.7,1.8
cvs at kolab.org
cvs at kolab.org
Thu Sep 6 10:47:00 CEST 2007
Author: gunnar
Update of /kolabrepository/server/kolabconf/lib/Kolab
In directory doto:/tmp/cvs-serv8044/lib/Kolab
Modified Files:
Conf.pm
Log Message:
Allow to use variable replacement within the template META section. This allows to use templates from external packages since we reduce the dependance on the dist_conf mechanism.
Index: Conf.pm
===================================================================
RCS file: /kolabrepository/server/kolabconf/lib/Kolab/Conf.pm,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- Conf.pm 13 Aug 2007 07:11:38 -0000 1.7
+++ Conf.pm 6 Sep 2007 08:46:58 -0000 1.8
@@ -49,7 +49,7 @@
&rebuildTemplates
&checkPermissions
) ]
-);
+ );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
@@ -64,23 +64,23 @@
my %haschanged = ();
sub fixup {
- my $file = shift;
- my $ownership = shift;
- my $perm = shift;
+ my $file = shift;
+ my $ownership = shift;
+ my $perm = shift;
- (my $owner, my $group) = split(/:/, $ownership, 2);
- my $uid = (getpwnam($owner))[2];
- my $gid = (getgrnam($group))[2];
- Kolab::log('T', sprintf("Changing permissions of %s to 0%o", $file, $perm ), KOLAB_DEBUG );
- if( chmod($perm, $file) != 1 ) {
- Kolab::log('T', "Unable to change permissions of `$file' to ".sprintf("0%o",$perm) . ": $!", KOLAB_ERROR);
- exit(1);
- }
- Kolab::log('T', "Changing owner of $file to $owner:$group ($uid:$gid)", KOLAB_DEBUG );
- if( chown($uid,$gid,$file) != 1 ) {
- Kolab::log('T', "Unable to change ownership of `$file' to $uid:$gid: $!", KOLAB_ERROR);
- exit(1);
- }
+ (my $owner, my $group) = split(/:/, $ownership, 2);
+ my $uid = (getpwnam($owner))[2];
+ my $gid = (getgrnam($group))[2];
+ Kolab::log('T', sprintf("Changing permissions of %s to 0%o", $file, $perm ), KOLAB_DEBUG );
+ if( chmod($perm, $file) != 1 ) {
+ Kolab::log('T', "Unable to change permissions of `$file' to ".sprintf("0%o",$perm) . ": $!", KOLAB_ERROR);
+ exit(1);
+ }
+ Kolab::log('T', "Changing owner of $file to $owner:$group ($uid:$gid)", KOLAB_DEBUG );
+ if( chown($uid,$gid,$file) != 1 ) {
+ Kolab::log('T', "Unable to change ownership of `$file' to $uid:$gid: $!", KOLAB_ERROR);
+ exit(1);
+ }
}
sub build {
@@ -134,12 +134,12 @@
while (<$template>) {
#Eat the meta data sections
if (/^KOLAB_META_START$/) {
- my $found_end;
- while (!$found_end) {
- $_ = <$template>;
- $found_end = /^KOLAB_META_END$/;
- }
+ my $found_end;
+ while (!$found_end) {
$_ = <$template>;
+ $found_end = /^KOLAB_META_END$/;
+ }
+ $_ = <$template>;
}
if (/\@{3}if (\S+?)\@{3}/) {
if ($Kolab::config{$1} && lc($Kolab::config{$1}) ne "false" ) {
@@ -167,55 +167,55 @@
s/\@{3}endif\@{3}\n?//;
} else {
while (/\@{3}([^\s\@]+?)(\|(.+?)\((.*)\))?\@{3}/) {
- my $attr = $1;
- my $fct = $3;
- my $args = $4;
- #print STDERR "attr=\"$attr\", fct=\"$fct\", args=\"$args\"\n";
- if ($Kolab::config{$attr}) {
- my $val = "";
- if( !$fct ) {
- if (ref $Kolab::config{$attr} eq "ARRAY") {
- $val = $Kolab::config{$attr}->[0];
- } else {
- $val = $Kolab::config{$attr};
- }
- } else {
- # Modifier functions
- SWITCH: {
- # Join function
- $fct eq 'join' && do {
- if (ref $Kolab::config{$attr} eq "ARRAY") {
- my @vals = @{$Kolab::config{$attr}} ;
- # We want to make sure subdomain.domain.tld comes before domain.tld
- my @length_sorted_vals = sort {length $a cmp length $b} @vals;
- $val = join ($args, @length_sorted_vals) ;
- } else {
- $val = $Kolab::config{$attr};
- }
- last SWITCH;
- };
- # Quote function
- $fct eq 'quote' && do {
- # slapd.conf compatible quoting
- $val = $Kolab::config{$attr};
- $val =~ s/"/\"/g;
- $val = '"'.$val.'"';
- last SWITCH;
+ my $attr = $1;
+ my $fct = $3;
+ my $args = $4;
+ #print STDERR "attr=\"$attr\", fct=\"$fct\", args=\"$args\"\n";
+ if ($Kolab::config{$attr}) {
+ my $val = "";
+ if( !$fct ) {
+ if (ref $Kolab::config{$attr} eq "ARRAY") {
+ $val = $Kolab::config{$attr}->[0];
+ } else {
+ $val = $Kolab::config{$attr};
+ }
+ } else {
+ # Modifier functions
+ SWITCH: {
+ # Join function
+ $fct eq 'join' && do {
+ if (ref $Kolab::config{$attr} eq "ARRAY") {
+ my @vals = @{$Kolab::config{$attr}} ;
+ # We want to make sure subdomain.domain.tld comes before domain.tld
+ my @length_sorted_vals = sort {length $a cmp length $b} @vals;
+ $val = join ($args, @length_sorted_vals) ;
+ } else {
+ $val = $Kolab::config{$attr};
+ }
+ last SWITCH;
+ };
+ # Quote function
+ $fct eq 'quote' && do {
+ # slapd.conf compatible quoting
+ $val = $Kolab::config{$attr};
+ $val =~ s/"/\"/g;
+ $val = '"'.$val.'"';
+ last SWITCH;
+ }
+ }
}
- }
+ s/\@{3}([^\s\@]+?)(\|.+?)?\@{3}/$val/;
+ last if ( $val eq "\@\@\@$attr\@\@\@" ); # prevent endless loop
+ } else {
+ # Only warn the user in case we are not skipping the section
+ ($skip == 0) && Kolab::log('T', "No configuration variable corresponding to `$1' exists", KOLAB_WARN);
+ s/\@{3}([^\s\@]+?)\@{3}//;
}
- s/\@{3}([^\s\@]+?)(\|.+?)?\@{3}/$val/;
- last if ( $val eq "\@\@\@$attr\@\@\@" ); # prevent endless loop
- } else {
- # Only warn the user in case we are not skipping the section
- ($skip == 0) && Kolab::log('T', "No configuration variable corresponding to `$1' exists", KOLAB_WARN);
- s/\@{3}([^\s\@]+?)\@{3}//;
- }
}
($skip == 0) && print $config $_;
- }
- }
-
+ }
+ }
+
$template->close;
$config->close;
@@ -246,8 +246,8 @@
$haschanged{'clamav'} = 1;
#} elsif ($cfg =~ /example/) {
} else {
- Kolab::log('T', "`$cfg' change detected ", KOLAB_DEBUG );
- $templatehaschanged{$tmpl} = 1;
+ Kolab::log('T', "`$cfg' change detected ", KOLAB_DEBUG );
+ $templatehaschanged{$tmpl} = 1;
}
Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG );
@@ -295,13 +295,13 @@
$Kolab::config{'ldap_port'},
$Kolab::config{'bind_dn'},
$Kolab::config{'bind_pw'}
- );
+ );
my $mesg = $ldap->search(
base => 'k=kolab,'.$Kolab::config{'base_dn'},
scope => 'base',
filter => '(objectclass=*)'
- );
+ );
if ($mesg->code) {
Kolab::log('T', "Unable to locate Postfix $map map entries in LDAP", KOLAB_ERROR);
exit(1);
@@ -333,8 +333,8 @@
my $rc = `diff -q $cfg $oldcfg`;
chomp($rc);
if ($rc) {
- Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG);
- $haschanged{'postfix'} = 1;
+ Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG);
+ $haschanged{'postfix'} = 1;
}
} else {
$haschanged{'postfix'} = 1;
@@ -364,8 +364,8 @@
my $cyrusconf;
my $cyrustemplate;
if (!($cyrustemplate = IO::File->new($keytemplate, 'r'))) {
- Kolab::log('T', "Unable to open configuration file `$keytemplate': $!", KOLAB_ERROR);
- exit(1);
+ Kolab::log('T', "Unable to open configuration file `$keytemplate': $!", KOLAB_ERROR);
+ exit(1);
}
if (!($cyrusconf = IO::File->new($cfg, 'w'))) {
@@ -414,8 +414,8 @@
my $rc = `diff -q $cfg $oldcfg`;
chomp($rc);
if ($rc) {
- Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG);
- $haschanged{'imapd'} = 1;
+ Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG);
+ $haschanged{'imapd'} = 1;
}
} else {
$haschanged{'imapd'} = 1;
@@ -451,13 +451,13 @@
$Kolab::config{'ldap_port'},
$Kolab::config{'bind_dn'},
$Kolab::config{'bind_pw'}
- );
+ );
my $mesg = $ldap->search(
base => $Kolab::config{'base_dn'},
scope => 'sub',
filter => '(&(mail=*)(objectclass=kolabgroupofnames))'
- );
+ );
if ($mesg->code) {
Kolab::log('T', 'Unable to locate Cyrus groups in LDAP', KOLAB_ERROR);
exit(1);
@@ -471,16 +471,16 @@
my $group = lc($ldapobject->get_value('mail')).":*:$count:";
my $userlist = $ldapobject->get_value('member', asref => 1);
foreach (@$userlist) {
- my $uid = $_;
- my $umesg = $ldap->search( base => $uid,
- scope => 'base',
- filter => '(objectClass=*)' );
- if ( $umesg && $umesg->code() <= 0 && $umesg->count() == 1 ) {
- my $mail;
- ($mail = $umesg->entry(0)->get_value('mail')) or
- ($mail = $umesg->entry(0)->get_value('uid'));
- $group .= lc($mail).',';
- }
+ my $uid = $_;
+ my $umesg = $ldap->search( base => $uid,
+ scope => 'base',
+ filter => '(objectClass=*)' );
+ if ( $umesg && $umesg->code() <= 0 && $umesg->count() == 1 ) {
+ my $mail;
+ ($mail = $umesg->entry(0)->get_value('mail')) or
+ ($mail = $umesg->entry(0)->get_value('uid'));
+ $group .= lc($mail).',';
+ }
}
$group =~ s/,$//;
print $groupconf $group . "\n";
@@ -515,7 +515,7 @@
exit(1);
}
- my $global_acl = <<'EOS';
+my $global_acl = <<'EOS';
# Domain specific access
access to filter=(&(objectClass=kolabInetOrgPerson)(mail=*@@@@domain@@@)(|(!(alias=*))(alias=*@@@@domain@@@)))
by group/kolabGroupOfNames="cn=@@@domain@@@,cn=domains,cn=internal,@@@base_dn@@@" write
@@ -531,28 +531,29 @@
EOS
- my $dom_acl1 = << 'EOS';
+my $dom_acl1 = << 'EOS';
# Access to domain groups
access to dn.children="cn=domains,cn=internal,@@@base_dn@@@"
by group/kolabGroupOfNames="cn=admin,cn=internal,@@@base_dn@@@" write
by group/kolabGroupOfNames="cn=maintainer,cn=internal,@@@base_dn@@@" write
by dn="cn=nobody,cn=internal,@@@base_dn@@@" read
EOS
- my $dom_acl2 = << 'EOS';
+
+my $dom_acl2 = << 'EOS';
by group/kolabGroupOfNames="cn=@@@domain@@@,cn=domains,cn=internal,@@@base_dn@@@" read
EOS
- my $dom_acl3 = << 'EOS';
- by * search stop
+my $dom_acl3 = << 'EOS';
+ by * search stop
EOS
- my $str;
+ my $str;
my $domain;
my @domains;
if( ref($Kolab::config{'postfix-mydestination'}) eq 'ARRAY' ) {
- @domains = @{$Kolab::config{'postfix-mydestination'}};
+ @domains = @{$Kolab::config{'postfix-mydestination'}};
} else {
- @domains =( $Kolab::config{'postfix-mydestination'} );
+ @domains =( $Kolab::config{'postfix-mydestination'} );
}
($str = $dom_acl1) =~ s/\@{3}base_dn\@{3}/$Kolab::config{'base_dn'}/g;
@@ -580,8 +581,8 @@
my $rc = `diff -q $cfg $oldcfg`;
chomp($rc);
if ($rc) {
- Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG);
- $haschanged{'slapd'} = 1;
+ Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG);
+ $haschanged{'slapd'} = 1;
}
} else {
$haschanged{'slapd'} = 1;
@@ -609,24 +610,24 @@
}
if( $Kolab::config{'is_master'} eq "true" ) {
- # Master setup
- my @kh;
- if( ref $Kolab::config{'kolabhost'} eq 'ARRAY' ) {
- @kh = @{$Kolab::config{'kolabhost'}};
- } else {
- @kh = ( $Kolab::config{'kolabhost'} );
- }
- for my $h ( @kh ) {
- next if lc($h) eq lc($Kolab::config{'fqdnhostname'});
- print $repl "replica uri=ldaps://$h\n"
- ." binddn=\"".$Kolab::config{'bind_dn'}."\"\n"
- ." bindmethod=simple credentials=".$Kolab::config{'bind_pw'}."\n\n";
- }
+ # Master setup
+ my @kh;
+ if( ref $Kolab::config{'kolabhost'} eq 'ARRAY' ) {
+ @kh = @{$Kolab::config{'kolabhost'}};
+ } else {
+ @kh = ( $Kolab::config{'kolabhost'} );
+ }
+ for my $h ( @kh ) {
+ next if lc($h) eq lc($Kolab::config{'fqdnhostname'});
+ print $repl "replica uri=ldaps://$h\n"
+ ." binddn=\"".$Kolab::config{'bind_dn'}."\"\n"
+ ." bindmethod=simple credentials=".$Kolab::config{'bind_pw'}."\n\n";
+ }
} else {
- # Slave setup
- # Output an update dn statement instead
- print $repl "updatedn ".$Kolab::config{'bind_dn'}."\n";
- print $repl "updateref ".$Kolab::config{'ldap_master_uri'}."\n";
+ # Slave setup
+ # Output an update dn statement instead
+ print $repl "updatedn ".$Kolab::config{'bind_dn'}."\n";
+ print $repl "updateref ".$Kolab::config{'ldap_master_uri'}."\n";
}
$repl->close;
@@ -637,8 +638,8 @@
my $rc = `diff -q $cfg $oldcfg`;
chomp($rc);
if ($rc) {
- Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG);
- $haschanged{'slapd'} = 1;
+ Kolab::log('T', "`$cfg' change detected: $rc", KOLAB_DEBUG);
+ $haschanged{'slapd'} = 1;
}
} else {
$haschanged{'slapd'} = 1;
@@ -647,68 +648,85 @@
Kolab::log('T', 'Finished building LDAP replicas', KOLAB_DEBUG);
}
+sub replaceMetaVar
+{
+ my $var = shift;
+
+ if ($var =~ /\@{3}([^\s\@]+?)\@{3}/) {
+ my $attr = $1;
+ if ($Kolab::config{$attr}) {
+ my $val = $Kolab::config{$attr};
+ $var =~ s/\@{3}([^\s\@]+?)\@{3}/$val/;
+ } else {
+ Kolab::log('T', "No configuration variable corresponding to `$1' exists", KOLAB_WARN);
+ }
+ }
+ return $var;
+}
+
+
sub loadMetaTemplates
{
- my $templatedir = shift;
- my ($tref, $pref, $oref, $cmdref) = @_;
+ my $templatedir = shift;
+ my ($tref, $pref, $oref, $cmdref) = @_;
- Kolab::log('T', 'Collecting template files', KOLAB_DEBUG );
- opendir(DIR, $templatedir) or Kolab::log('T', 'Given templatedir $templatedir does not exist!', KOLAB_ERROR );
- my @metatemplates = grep { /\.template$/ } readdir (DIR);
- closedir(DIR);
+ Kolab::log('T', 'Collecting template files', KOLAB_DEBUG );
+ opendir(DIR, $templatedir) or Kolab::log('T', 'Given templatedir $templatedir does not exist!', KOLAB_ERROR );
+ my @metatemplates = grep { /\.template$/ } readdir (DIR);
+ closedir(DIR);
- foreach my $template (@metatemplates) {
- my $runonchange = undef;
- #Open each file and check for the META
- if (open (TEMPLATE, "$templatedir/$template" )) {
- my $line = <TEMPLATE>;
- if ($line =~ /^KOLAB_META_START$/) {
- Kolab::log('T', 'Processing META template :'.$template, KOLAB_DEBUG );
- my ($found_end, $target, $permissions, $ownership);
- while (<TEMPLATE>) {
- $line = $_;
-
- if (!$found_end) {
- $found_end = $line =~ /^KOLAB_META_END$/;
- if (!$found_end && $line) {
- my ($key,$value) = split(/=/,$line);
- chomp($value);
- Kolab::log('T', 'META Key: '.$key.' Value: '.$value, KOLAB_DEBUG );
- if ($key =~ /^TARGET$/) {
- $target = $value;
- Kolab::log('T', 'META Target '.$target, KOLAB_DEBUG );
- }
- if ($key =~ /^PERMISSIONS$/) {
- $permissions = $value;
- Kolab::log('T', 'META Permissions '.$permissions, KOLAB_DEBUG );
- }
- if ($key =~ /^OWNERSHIP$/) {
- $ownership = $value;
- Kolab::log('T', 'META Ownership '.$ownership, KOLAB_DEBUG );
- }
- if ($key =~ /^RUNONCHANGE$/) {
- $runonchange = $value;
- Kolab::log('T', 'META Cmd to execute '.$runonchange, KOLAB_DEBUG );
- }
+ foreach my $template (@metatemplates) {
+ my $runonchange = undef;
+ #Open each file and check for the META
+ if (open (TEMPLATE, "$templatedir/$template" )) {
+ my $line = <TEMPLATE>;
+ if ($line =~ /^KOLAB_META_START$/) {
+ Kolab::log('T', 'Processing META template :'.$template, KOLAB_DEBUG );
+ my ($found_end, $target, $permissions, $ownership);
+ while (<TEMPLATE>) {
+ $line = $_;
+
+ if (!$found_end) {
+ $found_end = $line =~ /^KOLAB_META_END$/;
+ if (!$found_end && $line) {
+ my ($key,$value) = split(/=/,$line);
+ chomp($value);
+ Kolab::log('T', 'META Key: '.$key.' Value: '.$value, KOLAB_DEBUG );
+ if ($key =~ /^TARGET$/) {
+ $target = replaceMetaVar($value);
+ Kolab::log('T', 'META Target '.$target, KOLAB_DEBUG );
+ }
+ if ($key =~ /^PERMISSIONS$/) {
+ $permissions = replaceMetaVar($value);
+ Kolab::log('T', 'META Permissions '.$permissions, KOLAB_DEBUG );
+ }
+ if ($key =~ /^OWNERSHIP$/) {
+ $ownership = replaceMetaVar($value);
+ Kolab::log('T', 'META Ownership '.$ownership, KOLAB_DEBUG );
+ }
+ if ($key =~ /^RUNONCHANGE$/) {
+ $runonchange = replaceMetaVar($value);
+ Kolab::log('T', 'META Cmd to execute '.$runonchange, KOLAB_DEBUG );
+ }
- }
- }
- }
- if ($found_end && $target && $permissions && $ownership) {
- Kolab::log('T', 'All mandatory fields populated in '.$template, KOLAB_DEBUG );
- $$tref{$templatedir . "/" . $template} = $target;
- $$oref{$target} = $ownership;
- $permissions = oct($permissions);
- $$pref{$target} = $permissions;
- my $runcmdtemplate = $templatedir."/".$template;
- $$cmdref{$runcmdtemplate} = $runonchange if (defined $runonchange);
- }
-
}
- } else {
- Kolab::log('T', 'Could not open template file: '. $template, KOLAB_WARN);
+ }
+ }
+ if ($found_end && $target && $permissions && $ownership) {
+ Kolab::log('T', 'All mandatory fields populated in '.$template, KOLAB_DEBUG );
+ $$tref{$templatedir . "/" . $template} = $target;
+ $$oref{$target} = $ownership;
+ $permissions = oct($permissions);
+ $$pref{$target} = $permissions;
+ my $runcmdtemplate = $templatedir."/".$template;
+ $$cmdref{$runcmdtemplate} = $runonchange if (defined $runonchange);
}
+
+ }
+ } else {
+ Kolab::log('T', 'Could not open template file: '. $template, KOLAB_WARN);
}
+ }
}
@@ -727,9 +745,9 @@
loadMetaTemplates( $templatedir, \%templates, \%permissions, \%ownership, \%runonchange );
foreach $key (keys %templates) {
- my $tpl = $templates{$key};
- #print STDOUT "Rebuilding $key => $templates{$key}\n";
- build($key, $tpl, $ownership{$tpl}, $permissions{$tpl} );
+ my $tpl = $templates{$key};
+ #print STDOUT "Rebuilding $key => $templates{$key}\n";
+ build($key, $tpl, $ownership{$tpl}, $permissions{$tpl} );
}
buildPostfixTransportMap;
@@ -742,13 +760,13 @@
Kolab::log('T', 'Finished regenerating configuration files', KOLAB_DEBUG );
foreach $key (keys %runonchange) {
- if (defined $templatehaschanged{$key})
- {
- Kolab::log('T', 'Actioning RUNONCHANGE for $key', KOLAB_DEBUG );
- my $cmd = $runonchange{$key};
- system($cmd);
- Kolab::log('T', 'Executing command', KOLAB_DEBUG );
- }
+ if (defined $templatehaschanged{$key})
+ {
+ Kolab::log('T', 'Actioning RUNONCHANGE for $key', KOLAB_DEBUG );
+ my $cmd = $runonchange{$key};
+ system($cmd);
+ Kolab::log('T', 'Executing command', KOLAB_DEBUG );
+ }
}
}
@@ -765,27 +783,27 @@
my $ok = 1;
foreach $key (keys %templates) {
- my $tpl = $templates{$key};
+ my $tpl = $templates{$key};
- if (-r $tpl) {
- my $st = stat($tpl);
- my $owner = getpwuid($st->uid).':'.getgrgid($st->gid);
- if( ( ($st->mode & 07777) != $permissions{$tpl}) ||
- ($owner ne $ownership{$tpl}) ) {
- my $str = 'File '.$tpl.' has the wrong persmissions/owner. Found '
- .sprintf("%lo", $st->mode&07777).' '.$owner.', expected '
- .sprintf("%lo",$permissions{$tpl}).' '.$ownership{$tpl};
- print( "$str\n" );
- Kolab::log('T', $str, KOLAB_ERROR );
- $ok = 0;
- }
- } else {
- my $str = "File $tpl does not exist";
- print "$str\n";
- Kolab::log('T', "$str", KOLAB_ERROR );
- }
- }
- return $ok;
+ if (-r $tpl) {
+ my $st = stat($tpl);
+ my $owner = getpwuid($st->uid).':'.getgrgid($st->gid);
+ if( ( ($st->mode & 07777) != $permissions{$tpl}) ||
+ ($owner ne $ownership{$tpl}) ) {
+ my $str = 'File '.$tpl.' has the wrong persmissions/owner. Found '
+ .sprintf("%lo", $st->mode&07777).' '.$owner.', expected '
+ .sprintf("%lo",$permissions{$tpl}).' '.$ownership{$tpl};
+ print( "$str\n" );
+ Kolab::log('T', $str, KOLAB_ERROR );
+ $ok = 0;
+ }
+ } else {
+ my $str = "File $tpl does not exist";
+ print "$str\n";
+ Kolab::log('T', "$str", KOLAB_ERROR );
+ }
+ }
+ return $ok;
}
sub reload
More information about the commits
mailing list