You need to sign in or sign up before continuing.
Config.pm 11.9 KB
Newer Older
1 2 3
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
#
5 6
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
7 8 9 10 11 12

package Bugzilla::Config;

use strict;

use base qw(Exporter);
13
use Bugzilla::Constants;
14
use Bugzilla::Hook;
15
use Bugzilla::Install::Filesystem qw(fix_file_permissions);
16 17
use Data::Dumper;
use File::Temp;
18

19 20 21 22 23
# Don't export localvars by default - people should have to explicitly
# ask for it, as a (probably futile) attempt to stop code using it
# when it shouldn't
%Bugzilla::Config::EXPORT_TAGS =
  (
24
   admin => [qw(update_params SetParam write_params)],
25
  );
26
Exporter::export_ok_tags('admin');
27 28

# INITIALISATION CODE
29
# Perl throws a warning if we use bz_locations() directly after do.
30
our %params;
31
# Load in the param definitions
32
sub _load_params {
33
    my $panels = param_panels();
34
    my %hook_panels;
35 36 37
    foreach my $panel (keys %$panels) {
        my $module = $panels->{$panel};
        eval("require $module") || die $@;
38 39
        my @new_param_list = $module->get_param_list();
        $hook_panels{lc($panel)} = { params => \@new_param_list };
40
    }
41 42
    # This hook is also called in editparams.cgi. This call here is required
    # to make SetParam work.
43
    Bugzilla::Hook::process('config_modify_panels', 
44
                            { panels => \%hook_panels });
45 46 47 48 49 50

    foreach my $panel (keys %hook_panels) {
        foreach my $item (@{$hook_panels{$panel}->{params}}) {
            $params{$item->{'name'}} = $item;
        }
    }
51 52 53 54 55
}
# END INIT CODE

# Subroutines go here

56
sub param_panels {
57
    my $param_panels = {};
58 59 60 61
    my $libpath = bz_locations()->{'libpath'};
    foreach my $item ((glob "$libpath/Bugzilla/Config/*.pm")) {
        $item =~ m#/([^/]+)\.pm$#;
        my $module = $1;
62
        $param_panels->{$module} = "Bugzilla::Config::$module" unless $module eq 'Common';
63
    }
64
    # Now check for any hooked params
65
    Bugzilla::Hook::process('config_add_panels', 
66
                            { panel_modules => $param_panels });
67
    return $param_panels;
68 69
}

70 71 72
sub SetParam {
    my ($name, $value) = @_;

73
    _load_params unless %params;
74 75 76 77 78
    die "Unknown param $name" unless (exists $params{$name});

    my $entry = $params{$name};

    # sanity check the value
79 80

    # XXX - This runs the checks. Which would be good, except that
81 82
    # check_shadowdb creates the database as a side effect, and so the
    # checker fails the second time around...
83
    if ($name ne 'shadowdb' && exists $entry->{'checker'}) {
84 85 86 87
        my $err = $entry->{'checker'}->($value, $entry);
        die "Param $name is not valid: $err" unless $err eq '';
    }

88
    Bugzilla->params->{$name} = $value;
89 90
}

91 92
sub update_params {
    my ($params) = @_;
93
    my $answer = Bugzilla->installation_answers;
94 95

    my $param = read_param_file();
96
    my %new_params;
97 98 99

    # If we didn't return any param values, then this is a new installation.
    my $new_install = !(keys %$param);
100

101
    # --- UPDATE OLD PARAMS ---
102

103
    # Change from usebrowserinfo to defaultplatform/defaultopsys combo
104 105 106
    if (exists $param->{'usebrowserinfo'}) {
        if (!$param->{'usebrowserinfo'}) {
            if (!exists $param->{'defaultplatform'}) {
107
                $new_params{'defaultplatform'} = 'Other';
108
            }
109
            if (!exists $param->{'defaultopsys'}) {
110
                $new_params{'defaultopsys'} = 'Other';
111 112 113 114
            }
        }
    }

115
    # Change from a boolean for quips to multi-state
116
    if (exists $param->{'usequip'} && !exists $param->{'enablequips'}) {
117
        $new_params{'enablequips'} = $param->{'usequip'} ? 'on' : 'off';
118 119
    }

120 121
    # Change from old product groups to controls for group_control_map
    # 2002-10-14 bug 147275 bugreport@peshkin.net
122 123 124
    if (exists $param->{'usebuggroups'} && 
        !exists $param->{'makeproductgroups'}) 
    {
125
        $new_params{'makeproductgroups'} = $param->{'usebuggroups'};
126 127
    }

128
    # Modularise auth code
129
    if (exists $param->{'useLDAP'} && !exists $param->{'loginmethod'}) {
130
        $new_params{'loginmethod'} = $param->{'useLDAP'} ? "LDAP" : "DB";
131 132
    }

133
    # set verify method to whatever loginmethod was
134 135 136
    if (exists $param->{'loginmethod'} 
        && !exists $param->{'user_verify_class'}) 
    {
137
        $new_params{'user_verify_class'} = $param->{'loginmethod'};
138 139
    }

140 141
    # Remove quip-display control from parameters
    # and give it to users via User Settings (Bug 41972)
142 143
    if ( exists $param->{'enablequips'} 
         && !exists $param->{'quip_list_entry_control'}) 
144 145
    {
        my $new_value;
146 147 148 149
        ($param->{'enablequips'} eq 'on')       && do {$new_value = 'open';};
        ($param->{'enablequips'} eq 'approved') && do {$new_value = 'moderated';};
        ($param->{'enablequips'} eq 'frozen')   && do {$new_value = 'closed';};
        ($param->{'enablequips'} eq 'off')      && do {$new_value = 'closed';};
150
        $new_params{'quip_list_entry_control'} = $new_value;
151 152
    }

153 154 155 156 157 158 159 160 161 162 163 164 165
    # Old mail_delivery_method choices contained no uppercase characters
    if (exists $param->{'mail_delivery_method'}
        && $param->{'mail_delivery_method'} !~ /[A-Z]/) {
        my $method = $param->{'mail_delivery_method'};
        my %translation = (
            'sendmail' => 'Sendmail',
            'smtp'     => 'SMTP',
            'qmail'    => 'Qmail',
            'testfile' => 'Test',
            'none'     => 'None');
        $param->{'mail_delivery_method'} = $translation{$method};
    }

166 167 168
    # Convert the old "ssl" parameter to the new "ssl_redirect" parameter.
    # Both "authenticated sessions" and "always" turn on "ssl_redirect"
    # when upgrading.
169
    if (exists $param->{'ssl'} and $param->{'ssl'} ne 'never') {
170
        $new_params{'ssl_redirect'} = 1;
171
    }
172

173 174 175 176 177
    # "specific_search_allow_empty_words" has been renamed to "search_allow_no_criteria".
    if (exists $param->{'specific_search_allow_empty_words'}) {
        $new_params{'search_allow_no_criteria'} = $param->{'specific_search_allow_empty_words'};
    }

178 179
    # --- DEFAULTS FOR NEW PARAMS ---

180
    _load_params unless %params;
181 182
    foreach my $name (keys %params) {
        my $item = $params{$name};
183 184
        unless (exists $param->{$name}) {
            print "New parameter: $name\n" unless $new_install;
185 186 187 188
            if (exists $new_params{$name}) {
                $param->{$name} = $new_params{$name};
            }
            elsif (exists $answer->{$name}) {
189 190 191 192 193
                $param->{$name} = $answer->{$name};
            }
            else {
                $param->{$name} = $item->{'default'};
            }
194
        }
195 196
    }

197
    $param->{'utf8'} = 1 if $new_install;
198

199
    # --- REMOVE OLD PARAMS ---
200

201
    my %oldparams;
202
    # Remove any old params
203
    foreach my $item (keys %$param) {
204 205
        if (!exists $params{$item}) {
            $oldparams{$item} = delete $param->{$item};
206 207 208
        }
    }

209 210 211
    # Write any old parameters to old-params.txt
    my $datadir = bz_locations()->{'datadir'};
    my $old_param_file = "$datadir/old-params.txt";
212
    if (scalar(keys %oldparams)) {
213 214
        my $op_file = new IO::File($old_param_file, '>>', 0600)
          || die "Couldn't create $old_param_file: $!";
215 216 217

        print "The following parameters are no longer used in Bugzilla,",
              " and so have been\nmoved from your parameters file into",
218
              " $old_param_file:\n";
219

220 221 222 223 224 225 226 227
        local $Data::Dumper::Terse  = 1;
        local $Data::Dumper::Indent = 0;

        my $comma = "";
        foreach my $item (keys %oldparams) {
            print $op_file "\n\n$item:\n" . Data::Dumper->Dump([$oldparams{$item}]) . "\n";
            print "${comma}$item";
            $comma = ", ";
228 229 230 231 232 233
        }
        print "\n";
        $op_file->close;
    }

    if (ON_WINDOWS && !-e SENDMAIL_EXE
234
        && $param->{'mail_delivery_method'} eq 'Sendmail')
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
    {
        my $smtp = $answer->{'SMTP_SERVER'};
        if (!$smtp) {
            print "\nBugzilla requires an SMTP server to function on",
                  " Windows.\nPlease enter your SMTP server's hostname: ";
            $smtp = <STDIN>;
            chomp $smtp;
            if ($smtp) {
                $param->{'smtpserver'} = $smtp;
             }
             else {
                print "\nWarning: No SMTP Server provided, defaulting to",
                      " localhost\n";
            }
        }

251
        $param->{'mail_delivery_method'} = 'SMTP';
252 253 254
    }

    write_params($param);
255 256 257 258

    # Return deleted params and values so that checksetup.pl has a chance
    # to convert old params to new data.
    return %oldparams;
259 260
}

261 262 263 264 265 266
sub write_params {
    my ($param_data) = @_;
    $param_data ||= Bugzilla->params;

    my $datadir    = bz_locations()->{'datadir'};
    my $param_file = "$datadir/params";
267

268
    local $Data::Dumper::Sortkeys = 1;
269 270

    my ($fh, $tmpname) = File::Temp::tempfile('params.XXXXX',
271
                                              DIR => $datadir );
272

273
    print $fh (Data::Dumper->Dump([$param_data], ['*param']))
274 275 276 277
      || die "Can't write param file: $!";

    close $fh;

278
    rename $tmpname, $param_file
279
      or die "Can't rename $tmpname to $param_file: $!";
280

281
    fix_file_permissions($param_file);
282

283 284 285
    # And now we have to reset the params cache so that Bugzilla will re-read
    # them.
    delete Bugzilla->request_cache->{params};
286 287
}

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
sub read_param_file {
    my %params;
    my $datadir = bz_locations()->{'datadir'};
    if (-e "$datadir/params") {
        # Note that checksetup.pl sets file permissions on '$datadir/params'

        # Using Safe mode is _not_ a guarantee of safety if someone does
        # manage to write to the file. However, it won't hurt...
        # See bug 165144 for not needing to eval this at all
        my $s = new Safe;

        $s->rdo("$datadir/params");
        die "Error reading $datadir/params: $!" if $!;
        die "Error evaluating $datadir/params: $@" if $@;

        # Now read the param back out from the sandbox
        %params = %{$s->varglob('param')};
    }
306 307 308 309 310 311 312 313 314 315 316
    elsif ($ENV{'SERVER_SOFTWARE'}) {
       # We're in a CGI, but the params file doesn't exist. We can't
       # Template Toolkit, or even install_string, since checksetup
       # might not have thrown an error. Bugzilla::CGI->new
       # hasn't even been called yet, so we manually use CGI::Carp here
       # so that the user sees the error.
       require CGI::Carp;
       CGI::Carp->import('fatalsToBrowser');
       die "The $datadir/params file does not exist."
           . ' You probably need to run checksetup.pl.',
    }
317 318 319
    return \%params;
}

320 321 322 323 324 325 326 327 328 329 330 331 332
1;

__END__

=head1 NAME

Bugzilla::Config - Configuration parameters for Bugzilla

=head1 SYNOPSIS

  # Administration functions
  use Bugzilla::Config qw(:admin);

333
  update_params();
334
  SetParam($param, $value);
335
  write_params();
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353

=head1 DESCRIPTION

This package contains ways to access Bugzilla configuration parameters.

=head1 FUNCTIONS

=head2 Parameters

Parameters can be set, retrieved, and updated.

=over 4

=item C<SetParam($name, $value)>

Sets the param named $name to $value. Values are checked using the checker
function for the given param if one exists.

354
=item C<update_params()>
355 356

Updates the parameters, by transitioning old params to new formats, setting
357 358
defaults for new params, and removing obsolete ones. Used by F<checksetup.pl>
in the process of an installation or upgrade.
359

360
Prints out information about what it's doing, if it makes any changes.
361

362 363
May prompt the user for input, if certain required parameters are not
specified.
364

365
=item C<write_params($params)>
366

367
Description: Writes the parameters to disk.
368

369 370 371
Params:      C<$params> (optional) - A hashref to write to the disk
               instead of C<Bugzilla->params>. Used only by
               C<update_params>.
372

373
Returns:     nothing
374

375
=item C<read_param_file()>
376

377 378 379
Description: Most callers should never need this. This is used
             by C<Bugzilla->params> to directly read C<$datadir/params>
             and load it into memory. Use C<Bugzilla->params> instead.
380

381
Params:      none
382

383
Returns:     A hashref containing the current params in C<$datadir/params>.
384 385

=back