#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - autofixer2/webmail_scriptaliasmatch    Copyright(c) 2015 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

# Life is about progress, not perfection. Except for this file. We have to get this right on the first try, or we may
# never get it right again. So proceed with haste, because time is of the essence, but don't be in a hurry.

use strict;

package webmail_scriptaliasmatch;

BEGIN {
    exit 0 if ( $^X eq '/usr/bin/perl' ) || ( $^X eq '/usr/local/bin/perl' );
    unshift @INC, '/usr/local/cpanel';
}

use Cpanel::CPAN::YAML::Syck ();
use IO::Handle               ();

# We don't want to edit APACHE_CONFIG in place. That way lies madness. We will instead temporarily replace it with this
# one, to do just what we need, then restore the one cPanel provides.
our $main_yaml          = '/var/cpanel/conf/apache/main';
our $apache_config_name = '/usr/local/cpanel/APACHE_CONFIG';
our $APACHE_CONFIG      = <<'EOM';
ScriptAliasMatch ^/?webmail(/.*|/?)$ /usr/local/cpanel/cgi-sys/wredirect.cgi

*REMOVE* ScriptAlias /webmail /usr/local/cpanel/base/wredirect.cgi
*REMOVE* ScriptAlias /webmail /usr/local/cpanel/cgi-sys/wredirect.cgi
*REMOVE* ScriptAliasMatch ^/?webmail/?$ /usr/local/cpanel/cgi-sys/wredirect.cgi
*REMOVE* ScriptAliasMatch /webmail/(.*) /usr/local/cpanel/base/wredirect.cgi
*REMOVE* ScriptAliasMatch ^/webmail/(.*) /usr/local/cpanel/base/wredirect.cgi
*REMOVE* ScriptAliasMatch ^/?webmail/ /usr/local/cpanel/cgi-sys/wredirect.cgi
*REMOVE* ScriptAliasMatch ^/?webmail$ /usr/local/cpanel/cgi-sys/wredirect.cgi
*REMOVE* ScriptAliasMatch ^/webmail/(.*) /usr/local/cpanel/cgi-sys/wredirect.cgi
EOM

exit script() unless caller();

sub script {
    my $self = __PACKAGE__->new();
    $self->do_the_thing();
    return 0;
}

sub new {
    my ($class) = @_;
    my $self = bless {}, $class;

    # Move APACHE_CONFIG off to the side
    open( my $apache_config_fh, '+<', $apache_config_name ) or die "Couldn't open $apache_config_name: $!";
    my $SAVED_APACHE_CONFIG = do { local $/; <$apache_config_fh> };

    # Blow APACHE_CONFIG away in favor of our changes.
    seek( $apache_config_fh, 0, 0 );
    print {$apache_config_fh} $APACHE_CONFIG;
    truncate( $apache_config_fh, tell($apache_config_fh) );
    $apache_config_fh->flush();

    $self->{'apache_config_fh'}    = $apache_config_fh;
    $self->{'SAVED_APACHE_CONFIG'} = $SAVED_APACHE_CONFIG;

    return $self;
}

sub do_the_thing {
    my ($self) = @_;

    # local is ignored, because in my testing, even if local exists, the SAMs in main get used.
    my $main = slurp_yaml('/var/cpanel/conf/apache/main');

    # This is going to get run on systems with webmail SAMs, none of which will be correct.
    # Well, maybe not "none", but if there are any, they will be very, very few.
    my @sam_items = grep { $_->{regex} !~ m/webmail/ } @{ $main->{main}{scriptaliasmatch}{items} };
    push @sam_items,
      {
        'regex' => '^/?webmail(/.*|/?)$',
        'path'  => '/usr/local/cpanel/cgi-sys/wredirect.cgi'
      };
    $main->{'main'}{'scriptaliasmatch'}{'items'} = \@sam_items;

    # Order here matters.
    #
    # We must get APACHE_CONFIG into the state we want, run setupapache, then run the distiller. IOW,
    # get APACHE_CONFIG into the state we want, then httpd.conf, then apache/main (via the distiller),
    # then rebuild httpd.conf using the correct data.
    system('/usr/local/cpanel/setupapache');
    system( '/usr/local/cpanel/bin/apache_conf_distiller', '--update' );
    barf_yaml( $main_yaml, $main );
    system('/usr/local/cpanel/scripts/rebuildhttpdconf');
}

# Put APACHE_CONFIG back the way we found it.
sub DESTROY {
    my ($self)              = @_;
    my $apache_config_fh    = $self->{'apache_config_fh'};
    my $SAVED_APACHE_CONFIG = $self->{'SAVED_APACHE_CONFIG'};

    truncate( $apache_config_fh, 0 );
    seek( $apache_config_fh, 0, 0 );
    print {$apache_config_fh} $SAVED_APACHE_CONFIG;
    close $apache_config_fh;
}

sub slurp_yaml {
    my $path = shift;
    my $out;

    if ( open my $yaml_in, '<', $path ) {
        $out = eval {
            local $/;
            local $SIG{__WARN__};
            local $SIG{__DIE__};
            ( YAML::Syck::Load(<$yaml_in>) )[0];
        };
        close $yaml_in;
    }
    else { die "Couldn't open $path for reading: $!"; }

    return $out;
}

sub barf_yaml {
    my ( $path, $data ) = @_;

    if ( open my $yaml_out, '>', $path ) {
        my $yaml = YAML::Syck::Dump($data);
        print {$yaml_out} $yaml;
        close $yaml_out;
    }
    else { die "Couldn't open $path for writing: $!"; }

    return 1;
}

1;
