#!/usr/bin/perl -w
#
# The LearningOnline Network
#
# $Id: modify_config_files.pl,v 1.2 2004/08/10 20:26:02 matthew Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
###

=pod

=head1 NAME

B<modify_config_files.pl>

=head1 SYNOPSIS

This script modifies /etc/yum.conf and /etc/my.cnf.

=head1 DESCRIPTION

This script modifies /etc/yum.conf and /etc/my.cnf to ensure certain parameters
are set properly.  The LON-CAPA yum repositories are added to /etc/yum.conf.
The /etc/my.cnf file is modified to set the wait_timeout to 1 year.  Backup
copies of each file are made in /etc.

=cut

use strict;
use File::Copy;

&update_file('/etc/yum.conf',
             [{section => 'loncapa-updates-i386',
               key     => 'name=',
               value   => 'Fedora Core $releasever LON-CAPA i386 Updates',
           }, {section => 'loncapa-updates-i386',
               key     => 'baseurl=',
               value   => 'http://install.loncapa.org/fedora/linux/loncapa/'.
                   '$releasever/i386',
           }, {section => 'loncapa-updates-noarch',
               key     => 'name=',
               value   => 'Fedora Core $releasever LON-CAPA noarch Updates',
           }, {section => 'loncapa-updates-noarch',
               key     => 'baseurl=',
               value   => 'http://install.loncapa.org/fedora/linux/loncapa/'.
                   '$releasever/noarch',
           }]);

&update_file('/etc/my.cnf',
             [{section =>'mysqld',
               key     =>'set-variable=wait_timeout=',
               value   =>'31536000', }]);

exit;



#################################################################
#################################################################

=pod

=over 4

=cut

#################################################################
#################################################################
sub update_file {
    my ($file,$newdata) = @_;
    return 1 if (! -e $file);
    my $backup = $file.'.backup';
    if (! copy($file,$backup)) {
        warn "Error: Unable to make backup of $file";
        return 0;
    }
    my ($filedata) = &parse_config_file($file);
    if (! ref($filedata)) { warn "Error: $filedata"; return 0;}
    foreach my $data (@$newdata) {
        my $section = $data->{'section'};
        my $key = $data->{'key'};
        my $value = $data->{'value'};
        &modify_config_file($filedata,$section,$key,$value)
    }
    my $result = &write_config_file($file,$filedata);
    if (defined($result)) { warn 'Error:'.$result; return 0; }
    return 1;
}

#################################################################
#################################################################

=pod

=item &parse_config_file

Read a configuration file in and parse it into an internal data structure.

Input: filename

Output: array ref $filedata  OR  scalar error message

=cut

#################################################################
#################################################################
sub parse_config_file {
    my ($file) = @_;
    open(INFILE,$file) || return ('Unable to open '.$file.' for reading');
    my @Input = <INFILE>;
    close(INFILE);
    my @Structure;
    my %Sections;
    while (my $line = shift(@Input)) {
        chomp($line);
        if ($line =~ /^\[([^\]]*)\]/) {
            my $section_id = $1;
            push(@Structure,'__section__'.$section_id);
            while ($line = shift(@Input)) {
                if ($line =~ /^\[([^\]]*)\]/) {
                    unshift(@Input,$line);
                    last;
                } else {
                    push(@{$Sections{$section_id}},$line);
                }
            }
        } else {
            push(@Structure,$line);
        }
    }
    my $filedata = [\@Structure,\%Sections];
    return $filedata;
}

#################################################################
#################################################################

=pod

=item

Write a configuration file out based on the internal data structure returned
by &parse_config_file

Inputs: filename, $filedata (the return value of &parse_config_file

Returns: undef on success, scalar error message on failure.

=cut

#################################################################
#################################################################
sub write_config_file {
    my ($file,$filedata) = @_;
    my ($structure,$sections) = @$filedata;
    if (! defined($structure) || ! ref($structure)) {
        return 'Bad subroutine inputs';
    }
    open(OUTPUT,'>'.$file) || return('Unable to open '.$file.' for writing');
    for (my $i=0;$i<scalar(@$structure);$i++) {
        my $line = $structure->[$i];
        chomp($line);
        if ($line =~ /^__section__(.*)$/) {
            my $section_id = $1;
            print OUTPUT ('['.$section_id.']'.$/);
            foreach my $section_line (@{$sections->{$section_id}}) {
                chomp($section_line);
                print OUTPUT $section_line.$/;
            }
            # Deal with blank lines
            if ($sections->{$section_id}->[-1] =~ /^\s*$/) {
                # No need to output a blank line at the end if there is one 
                # already
            } else {
                print OUTPUT $/;
            }
        } else {
            print OUTPUT $line.$/;
        }
    }
    close OUTPUT;
    return undef;
}

#################################################################
#################################################################

=pod

=item &modify_config_file

Modifies the internal data structure of a configuration file to include new
sections and/or new configuration directives.

Inputs: $filedata (see &parse_config_file
$section, the [section] the new entry is to reside in.  A value of undef will
cause the "outer" section (as in yum.conf) to be updated (or have the new
value prepended).
$newkey: A line which matches this will be replaced with $newkey.$newvalue
$newvalue: The new value to be placed with the new key.

=cut

#################################################################
#################################################################
sub modify_config_file {
    my ($filedata,$section,$newkey,$newvalue)=@_;
    my ($structure,$sections) = @$filedata;
    if (! defined($newvalue)) {
        $newvalue = '';
    }
    my $newline = $newkey.$newvalue;
    #
    # Determine which array ref gets the item
    my $target;
    if (defined($section)) {
        if (! exists($sections->{$section})) {
            push(@$structure,'__section__'.$section);
            $sections->{$section}=[];
        }
        $target = $sections->{$section};
    } else {
        $target = $structure;
    }
    #
    # Put the item in or update it.
    my $key_is_new = 1;
    for (my $i=0;$i<scalar(@$target);$i++) {
        
        if ($target->[$i] =~/^$newkey/) {
            $target->[$i]=$newline;
            $key_is_new = 0;
            last;
        }
    }
    if ($key_is_new) {
        if (! defined($section)) {
            unshift(@$target,$newline);
        } else {
            # No need to put things after a blank line.
            if (defined($target->[-1]) && $target->[-1] =~ /^\s*$/) {
                $target->[-1] = $newline;
            } else {
                push(@$target,$newline);
            }
        }
    }
    return ($filedata);
}


#################################################################
#################################################################

=pod

=back

=cut

#################################################################
#################################################################
