diff options
Diffstat (limited to 'FS/FS/Conf.pm')
-rw-r--r-- | FS/FS/Conf.pm | 263 |
1 files changed, 126 insertions, 137 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 5f7cb8fec..1c552a4bd 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -1,14 +1,13 @@ package FS::Conf; -use vars qw($base_dir @config_items @card_types $DEBUG ); -use MIME::Base64; +use vars qw($default_dir $base_dir @config_items @card_types $DEBUG ); +use IO::File; +use File::Basename; use FS::ConfItem; use FS::ConfDefaults; -use FS::conf; -use FS::Record qw(qsearch qsearchs); -use FS::UID qw(dbh); $base_dir = '%%%FREESIDE_CONF%%%'; +$default_dir = '%%%FREESIDE_CONF%%%'; $DEBUG = 0; @@ -21,8 +20,13 @@ FS::Conf - Freeside configuration values use FS::Conf; + $conf = new FS::Conf "/config/directory"; + + $FS::Conf::default_dir = "/config/directory"; $conf = new FS::Conf; + $dir = $conf->dir; + $value = $conf->config('key'); @list = $conf->config('key'); $bool = $conf->exists('key'); @@ -42,19 +46,39 @@ but this may change in the future. =over 4 -=item new +=item new [ DIRECTORY ] -Create a new configuration object. +Create a new configuration object. A directory arguement is required if +$FS::Conf::default_dir has not been set. =cut sub new { - my($proto) = @_; + my($proto,$dir) = @_; my($class) = ref($proto) || $proto; - my($self) = { 'base_dir' => $base_dir }; + my($self) = { 'dir' => $dir || $default_dir, + 'base_dir' => $base_dir, + }; bless ($self, $class); } +=item dir + +Returns the conf directory. + +=cut + +sub dir { + my($self) = @_; + my $dir = $self->{dir}; + -e $dir or die "FATAL: $dir doesn't exist!"; + -d $dir or die "FATAL: $dir isn't a directory!"; + -r $dir or die "FATAL: Can't read $dir!"; + -x $dir or die "FATAL: $dir not searchable (executable)!"; + $dir =~ /^(.*)$/; + $1; +} + =item base_dir Returns the base directory. By default this is /usr/local/etc/freeside. @@ -78,29 +102,20 @@ Returns the configuration value or values (depending on context) for key. =cut -sub _config { - my($self,$name,$agent)=@_; - my $hashref = { 'name' => $name }; - if (defined($agent) && $agent) { - $hashref->{agent} = $agent; - } - local $FS::Record::conf = undef; # XXX evil hack prevents recursion - my $cv = FS::Record::qsearchs('conf', $hashref); - if (!$cv && exists($hashref->{agent})) { - delete($hashref->{agent}); - $cv = FS::Record::qsearchs('conf', $hashref); - } - return $cv; -} - sub config { - my($self,$name,$agent)=@_; - my $cv = $self->_config($name, $agent) or return; - + my($self,$file)=@_; + my($dir)=$self->dir; + my $fh = new IO::File "<$dir/$file" or return; if ( wantarray ) { - split "\n", $cv->value; + map { + /^(.*)$/ + or die "Illegal line (array context) in $dir/$file:\n$_\n"; + $1; + } <$fh>; } else { - (split("\n", $cv->value))[0]; + <$fh> =~ /^(.*)$/ + or die "Illegal line (scalar context) in $dir/$file:\n$_\n"; + $1; } } @@ -111,9 +126,12 @@ Returns the exact scalar value for key. =cut sub config_binary { - my($self,$name,$agent)=@_; - my $cv = $self->_config($name, $agent) or return; - decode_base64($cv->value); + my($self,$file)=@_; + my($dir)=$self->dir; + my $fh = new IO::File "<$dir/$file" or return; + local $/; + my $content = <$fh>; + $content; } =item exists KEY @@ -124,8 +142,9 @@ is undefined. =cut sub exists { - my($self,$name,$agent)=@_; - defined($self->_config($name, $agent)); + my($self,$file)=@_; + my($dir) = $self->dir; + -e "$dir/$file"; } =item config_orbase KEY SUFFIX @@ -136,11 +155,11 @@ KEY_SUFFIX, if it exists, otherwise for KEY =cut sub config_orbase { - my( $self, $name, $suffix ) = @_; - if ( $self->exists("${name}_$suffix") ) { - $self->config("${name}_$suffix"); + my( $self, $file, $suffix ) = @_; + if ( $self->exists("${file}_$suffix") ) { + $self->config("${file}_$suffix"); } else { - $self->config($name); + $self->config($file); } } @@ -151,8 +170,12 @@ Creates the specified configuration key if it does not exist. =cut sub touch { - my($self, $name, $agent) = @_; - $self->set($name, '', $agent); + my($self, $file) = @_; + my $dir = $self->dir; + unless ( $self->exists($file) ) { + warn "[FS::Conf] TOUCH $file\n" if $DEBUG; + system('touch', "$dir/$file"); + } } =item set KEY VALUE @@ -162,41 +185,23 @@ Sets the specified configuration key to the given value. =cut sub set { - my($self, $name, $value, $agent) = @_; + my($self, $file, $value) = @_; + my $dir = $self->dir; $value =~ /^(.*)$/s; $value = $1; - - warn "[FS::Conf] SET $file\n" if $DEBUG; - - my $old = FS::Record::qsearchs('conf', {name => $name, agent => $agent}); - my $new = new FS::conf { $old ? $old->hash - : ('name' => $name, 'agent' => $agent) - }; - $new->value($value); - - my $error; - if ($old) { - $error = $new->replace($old); - } else { - $error = $new->insert; + unless ( join("\n", @{[ $self->config($file) ]}) eq $value ) { + warn "[FS::Conf] SET $file\n" if $DEBUG; +# warn "$dir" if is_tainted($dir); +# warn "$dir" if is_tainted($file); + chmod 0644, "$dir/$file"; + my $fh = new IO::File ">$dir/$file" or return; + chmod 0644, "$dir/$file"; + print $fh "$value\n"; } - - die "error setting configuration value: $error \n" - if $error; - -} - -=item set_binary KEY VALUE - -Sets the specified configuration key to an exact scalar value which -can be retrieved with config_binary. - -=cut - -sub set_binary { - my($self,$name, $value, $agent)=@_; - $self->set($name, encode_base64($value), $agent); } +#sub is_tainted { +# return ! eval { join('',@_), kill 0; 1; }; +# } =item delete KEY @@ -205,23 +210,11 @@ Deletes the specified configuration key. =cut sub delete { - my($self, $name, $agent) = @_; - if ( my $cv = FS::Record::qsearchs('conf', {name => $name, agent => $agent}) ) { + my($self, $file) = @_; + my $dir = $self->dir; + if ( $self->exists($file) ) { warn "[FS::Conf] DELETE $file\n"; - - my $oldAutoCommit = $FS::UID::AutoCommit; - local $FS::UID::AutoCommit = 0; - my $dbh = dbh; - - my $error = $cv->delete; - - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - die "error setting configuration value: $error \n" - } - - $dbh->commit or die $dbh->errstr if $oldAutoCommit; - + unlink "$dir/$file"; } } @@ -237,68 +230,65 @@ sub config_items { #quelle kludge @config_items, ( map { + my $basename = basename($_); + $basename =~ /^(.*)$/; + $basename = $1; new FS::ConfItem { - 'key' => $_->name, + 'key' => $basename, 'section' => 'billing', 'description' => 'Alternate template file for invoices. See the <a href="../docs/billing.html">billing documentation</a> for details.', 'type' => 'textarea', } - } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_template!_%' ESCAPE '!'") + } glob($self->dir. '/invoice_template_*') ), ( map { + my $basename = basename($_); + $basename =~ /^(.*)$/; + $basename = $1; new FS::ConfItem { - 'key' => '$_->name', - 'section' => 'billing', #? - 'description' => 'An image to include in some types of invoices', - 'type' => 'binary', - } - } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'logo!_%.png' ESCAPE '!'") - ), - ( map { - new FS::ConfItem { - 'key' => $_->name, + 'key' => $basename, 'section' => 'billing', 'description' => 'Alternate HTML template for invoices. See the <a href="../docs/billing.html">billing documentation</a> for details.', 'type' => 'textarea', } - } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_html!_%' ESCAPE '!'") + } glob($self->dir. '/invoice_html_*') ), ( map { - ($latexname = $_->name ) =~ s/latex/html/; + my $basename = basename($_); + $basename =~ /^(.*)$/; + $basename = $1; + ($latexname = $basename ) =~ s/latex/html/; new FS::ConfItem { - 'key' => $_->name, + 'key' => $basename, 'section' => 'billing', 'description' => "Alternate Notes section for HTML invoices. Defaults to the same data in $latexname if not specified.", 'type' => 'textarea', } - } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_htmlnotes!_%' ESCAPE '!'") + } glob($self->dir. '/invoice_htmlnotes_*') ), ( map { + my $basename = basename($_); + $basename =~ /^(.*)$/; + $basename = $1; new FS::ConfItem { - 'key' => $_->name, + 'key' => $basename, 'section' => 'billing', 'description' => 'Alternate LaTeX template for invoices. See the <a href="../docs/billing.html">billing documentation</a> for details.', 'type' => 'textarea', } - } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_latex!_%' ESCAPE '!'") - ), - ( map { - new FS::ConfItem { - 'key' => '$_->name', - 'section' => 'billing', #? - 'description' => 'An image to include in some types of invoices', - 'type' => 'binary', - } - } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'logo!_%.eps' ESCAPE '!'") + } glob($self->dir. '/invoice_latex_*') ), ( map { + my $basename = basename($_); + $basename =~ /^(.*)$/; + $basename = $1; new FS::ConfItem { - 'key' => $_->name, + 'key' => $basename, 'section' => 'billing', 'description' => 'Alternate Notes section for LaTeX typeset PostScript invoices. See the <a href="../docs/billing.html">billing documentation</a> for details.', 'type' => 'textarea', } - } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_latexnotes!_%' ESCAPE '!'") + } glob($self->dir. '/invoice_latexnotes_*') ); } @@ -1852,6 +1842,26 @@ httemplate/docs/config.html 'type' => 'checkbox', }, + #these should become per-user... + { + 'key' => 'vonage-username', + 'section' => '', + 'description' => 'Vonage Click2Call username (see <a href="https://secure.click2callu.com/">https://secure.click2callu.com/</a>)', + 'type' => 'text', + }, + { + 'key' => 'vonage-password', + 'section' => '', + 'description' => 'Vonage Click2Call username (see <a href="https://secure.click2callu.com/">https://secure.click2callu.com/</a>)', + 'type' => 'text', + }, + { + 'key' => 'vonage-fromnumber', + 'section' => '', + 'description' => 'Vonage Click2Call number (see <a href="https://secure.click2callu.com/">https://secure.click2callu.com/</a>)', + 'type' => 'text', + }, + { 'key' => 'echeck-nonus', 'section' => 'billing', @@ -2036,27 +2046,6 @@ httemplate/docs/config.html }, { - 'key' => 'logo.png', - 'section' => 'billing', #? - 'description' => 'An image to include in some types of invoices', - 'type' => 'binary', - }, - - { - 'key' => 'logo.eps', - 'section' => 'billing', #? - 'description' => 'An image to include in some types of invoices', - 'type' => 'binary', - }, - - { - 'key' => 'selfservice-ignore_quantity', - 'section' => '', - 'description' => 'Ignores service quantity restrictions in self-service context. Strongly not recommended - just set your quantities correctly in the first place.', - 'type' => 'checkbox', - }, - - { 'key' => 'disable_setup_suspended_pkgs', 'section' => 'billing', 'description' => 'Disables charging of setup fees for suspended packages.', |