package Cpanel::Easy::Apache::PHPAsUser;

# cpanel - Cpanel/Easy/Apache/PHPAsUser.pm        Copyright(c) 2014 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

my $version = '0.7.2';

our $easyconfig = {
    'version'   => $version,
    'name'      => qq{Mod SuPHP $version},
    'url'       => 'http://suphp.org/',
    'hastargz'  => 1,
    'haspatch'  => 0,
    'src_cd2'   => 'suphp-0',
    'depends'   => { 'optmods' => { 'Cpanel::Easy::Apache::Mime' => 0 }, },
    'ensurepkg' => ['libstdc++-devel.x86_64'],                                # workaround for http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=215839
    'implies'   => {
        'Cpanel::Easy::PHP5::CGI' => 0,                                       # this is reverse opt mods
    },
    'modself' => sub {
        my ( $easy, $self_hr, $profile_hr ) = @_;
        my %onlys;
        @onlys{ $easy->get_param('only') } = ();
        if ( ( exists $onlys{'Apache::PHPAsUser'} || exists $onlys{'Cpanel::Easy::Apache::PHPAsUser'} ) && !exists $onlys{'Apache'} && !exists $onlys{'Apache::Cpanel::Easy'} ) {
            delete $self_hr->{'step'}{'2'};
            %{$self_hr} = %{ $easy->merge_easyconfig_hrs_into_one( $self_hr, $Cpanel::Easy::Apache::PHPAsUser::buildsteps ) };
        }
    },
    'step' => {
        '0' => {
            'name'    => 'Setting version variable',
            'command' => sub {
                my ($self) = @_;

                # really so that this and it's ap1 couterpart woudld have the same number of steps so as to overwirte completely the other
                $self->{'_'}{'ap_ver'}    = $self->{'working_profile'}{'Apache'}{'version'};    # *NOT* $self->{'__'} since its localized
                $self->{'_'}{'suphp_dir'} = $self->cwd();
                return ( 1, 'Ok' );
              }
        },
        '1' => {
            'name'    => 'Patching mod_suphp',
            'command' => sub {
                my $self    = shift;
                my @patches = qw(
                  01_suphp_paths.patch
                  02_suphp_userdir.patch
                  03_suphp_full_php_process_display.patch
                  04_suphp_paranoid_checks.patch
                  05_suphp_phprc.patch
                  07_suphp_apache24_detect.patch
                );

                if ( $self->get_ns_value_from_profile( 'Cpanel::Easy::ModRuid2', $self->{'working_profile'} ) ) {
                    push @patches, '06_suphp_ruid2.patch';
                }
                foreach my $patch (@patches) {
                    my @rc = $self->apply_patch( '../cppatch/' . $patch );
                    return @rc if !$rc[0];
                }
                return ( 1, 'Ok' );
            },
        },
        '2' => {
            'name'    => 'Create task list to do after apache is built',
            'command' => sub {
                my ($self) = @_;

                return $self->add_to_modify_later_queue( 'Cpanel::Easy::Apache::' . $self->{'_'}{'ap_ver'}, $Cpanel::Easy::Apache::PHPAsUser::buildsteps, );
            },
        },
    },
};

our $buildsteps = {
    'step' => {
        '6.2' => {
            'name'    => 'resetting autotools timestamps',
            'command' => sub {
                my ($self) = @_;

                my $start = $self->cwd();
                chdir $self->{'_'}{'suphp_dir'} or return ( 0, q{Could not chdir into '[_1]: [_2]'}, $self->{'_'}{'suphp_dir'}, $! );

                unless ( -e '../suphp.conf' ) {
                    chdir $start;
                    return ( 0, 'suphp.conf is missing' ) if !-e '../suphp.conf';
                }

                # simple method to avoid invoking autotools scripts
                my @cmd = ('find ./ -exec touch -r ../suphp.conf \{\} \;');

                my @return = $self->run_system_cmd_returnable( \@cmd );

                chdir $start or return ( 0, q{Could not chdir back into '[_1]': [_2]}, $start, $! );
                return @return;
            },
        },
        '6.3' => {
            'name'    => 'APXSing mod_suphp into apache - configure',
            'command' => sub {
                my ($self) = @_;

                my $start = $self->cwd();
                chdir $self->{'_'}{'suphp_dir'} or return ( 0, q{Could not chdir into '[_1]: [_2]'}, $self->{'_'}{'suphp_dir'}, $! );

                my $apr_config = '--with-apr=/usr/local/apache/bin/apr-1-config';

                $self->add_to_configure( $self->get_raw_opts_if_any('all_suphp'), __PACKAGE__ );
                my $raw = $self->get_configure_as_string(__PACKAGE__);
                $raw = $raw ? " $raw" : '';

                local $ENV{'LDFLAGS'} = $ENV{'LDFLAGS'} . ' -lstdc++';

                my @config = (

                    qw(./configure --prefix=/opt/suphp --with-apxs=/usr/local/apache/bin/apxs --with-logfile=/usr/local/apache/logs/suphp_log),
                    $apr_config,
                    '--with-apache-user=nobody' . $raw,
                );

                my @return = $self->run_system_cmd_returnable( \@config );

                chdir $start or return ( 0, q{Could not chdir back into '[_1]': [_2]}, $start, $! );
                return @return;
            },
        },
        '6.4' => {
            'name'    => 'APXSing mod_suphp into apache - make',
            'command' => sub {
                my ($self) = @_;

                my $start = $self->cwd();
                chdir $self->{'_'}{'suphp_dir'} or return ( 0, q{Could not chdir into '[_1]: [_2]'}, $self->{'_'}{'suphp_dir'}, $! );

                my @return = $self->run_system_cmd_returnable( ['make'] );

                chdir $start or return ( 0, q{Could not chdir back into '[_1]': [_2]}, $start, $! );
                return @return;
            },
        },
        '6.5' => {
            'name'    => 'APXSing mod_suphp into apache - make install',
            'command' => sub {
                my ($self) = @_;

                my $start      = $self->cwd();
                my $suphp_mode = -1;
                if ( -e '/opt/suphp/sbin/suphp' ) {
                    $suphp_mode = ( stat(_) )[2];
                }

                chdir $self->{'_'}{'suphp_dir'} or return ( 0, q{Could not chdir into '[_1]: [_2]'}, $self->{'_'}{'suphp_dir'}, $! );
                my @cmd = qw( make install );
                my @return = $self->run_system_cmd_returnable( [@cmd] );

                if ( $suphp_mode != -1 ) {
                    chmod( $suphp_mode, '/opt/suphp/sbin/suphp' );
                }

                chdir $start or return ( 0, q{Could not chdir back into '[_1]': [_2]}, $start, $! );
                return @return;
            },
        },
        '6.6' => {
            'name'    => 'suphp.conf setup',
            'command' => sub {
                my ($self) = @_;

                my $target_dir = '/opt/suphp/etc/';

                my $start = $self->cwd();
                chdir $self->{'_'}{'suphp_dir'} or return ( 0, q{Could not chdir into '[_1]: [_2]'}, $self->{'_'}{'suphp_dir'}, $! );

                mkdir $target_dir if !-d $target_dir;

                my $suphp_conf = '../suphp.conf';

                # Preserve local modifications if cPanel supplied suphp.conf hasn't been updated
                # This also allows them to prevent any replacement ever by changing the version
                # number in suphp.conf with an arbitrarily large value
                if ( -e $target_dir . 'suphp.conf' ) {
                    my $suphp_conf_fh;
                    open $suphp_conf_fh, '<', $suphp_conf;
                    my $src_version;
                    do {
                        local $/;
                        $src_version = readline($suphp_conf_fh);
                    };
                    close $suphp_conf_fh;

                    if ( $src_version =~ /cPanel suphp\.conf version -- (\d+)/ ) {
                        $src_version = $1;
                    }
                    else {
                        $src_version = 42;
                    }

                    open $suphp_conf_fh, '<', $target_dir . 'suphp.conf';
                    my $dest_version;
                    do {
                        local $/;
                        $dest_version = readline($suphp_conf_fh);
                    };
                    close $suphp_conf_fh;

                    if ( $dest_version =~ /cPanel suphp\.conf version -- (\d+)/ ) {
                        $dest_version = $1;
                    }
                    else {
                        $dest_version = 1;
                    }

                    return ( 1, 'Ok' ) if ( $dest_version >= $src_version );

                    if ( $src_version eq '47' && ( $dest_version eq '43' || $dest_version eq '44' || $dest_version eq '45' || $dest_version eq '46' ) ) {

                        # version 44 added the phprc configuration
                        my $needs_phprc = $dest_version eq '43';
                        my $phprc_text  = "\n[phprc_paths]\n;Uncommenting these will force all requests to that handler to use the php.ini\n;in the specified directory regardless of suPHP_ConfigPath settings.\n;application/x-httpd-php=/usr/local/lib/\n;application/x-httpd-php5=/usr/local/lib/\n";

                        # version 45 added the full process display option
                        my $needs_full_process = $dest_version eq '43' || $dest_version eq '44';
                        my $full_process_text = "\n; Normally suPHP only displays the PHP binary in process lists (ps aux).\n; Setting this option to 'true' will cause suPHP to display both the\n; PHP binary and the script filename.\nfull_php_process_display=true\n\n";

                        # version 46 transitions to 0.7.x conf file syntax and removes the execute!self handler by default
                        my $conf_07 = $dest_version eq '43' || $dest_version eq '44' || $dest_version eq '45';

                        # In version 46 we forgot to quote the env_path setting
                        my $needs_env_path = $dest_version eq '43' || $dest_version eq '44' || $dest_version eq '45' || $dest_version eq '46';

                        if ( open $suphp_conf_fh, '+<', $target_dir . 'suphp.conf' ) {
                            my @orig_suphp_conf = <$suphp_conf_fh>;
                            seek( $suphp_conf_fh, 0, 0 );
                            my $in_handlers_section = 0;
                            while ( my $line = shift @orig_suphp_conf ) {
                                if ( $line =~ /^\s*\[handlers\]/ ) {
                                    $in_handlers_section = 1;
                                    if ($needs_full_process) {
                                        print $suphp_conf_fh $full_process_text;
                                        $needs_full_process = 0;
                                    }
                                }
                                elsif ( $line =~ /^\s*\[/ ) {
                                    $in_handlers_section = 0;
                                }
                                if ( $in_handlers_section && $conf_07 && $line !~ /^\s*(;.*|\[.*|\s*)$/ ) {
                                    if ( $line =~ /^\s*(\S+)=(php|execute):(.+)$/ ) {
                                        my $mime   = $1;
                                        my $mode   = $2;
                                        my $binary = $3;
                                        $binary =~ s/(^\s+|\s+$)//g;
                                        $line = ( $mode eq 'execute' ? ';' : '' ) . qq(${mime}="${mode}:${binary}"\n);
                                    }
                                }
                                if ( $needs_env_path && $line =~ /^\s*(;?)\s*env_path\s*=\s*([^"\s]+)/ ) {
                                    $line = qq{$1env_path="$2"\n};
                                }
                                $line =~ s/cPanel suphp\.conf version -- \d+/cPanel suphp\.conf version -- $src_version/;
                                print $suphp_conf_fh $line;
                            }
                            if ($needs_full_process) {
                                print $suphp_conf_fh $full_process_text;
                            }
                            if ($needs_phprc) {

                                # Add PHPRC section to end
                                print $suphp_conf_fh $phprc_text;
                            }
                            truncate $suphp_conf_fh, tell($suphp_conf_fh);
                            close $suphp_conf_fh;

                            return ( 1, 'Ok' );
                        }
                    }
                }

                my @return = $self->copy_file( $suphp_conf, '/opt/suphp/etc/suphp.conf' );

                chdir $start or return ( 0, q{Could not chdir back into '[_1]': [_2]}, $start, $! );
                return @return;
            },
        },
    },
};

1;
