package Cpanel::Easy::Apache::UI::HTML;

# cpanel - Cpanel/Easy/Apache/UI/HTML.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

use Whostmgr::HTMLInterface ();
use Cpanel::Encoder         ();
require YAML::Syck;    # already loaded, but for good measure
use Cpanel::CPAN::Text::InHTML       ();
use Cpanel::Template                 ();
use Cpanel::Version::Compare         ();
use Cpanel::Version::Tiny            ();
use JSON::Syck                       ();
use Cpanel::CPAN::MIME::Base64::Perl ();

use base 'Cpanel::Easy::Apache::UI::Utils';

our $layover_safe_profile_details =
  qq{<p>An EasyApache profile is a plain text YAML format file in /var/cpanel/easy/apache/profile/custom/ with a .yaml extention. A profile contains all the info necessary to build Apache and related modules how you want. It can be downloaded for distribution to other servers for reuse.</p><p>Even though you can edit it it\\'s recommended to create them via EasyApache\\'s &quot;Save As&quot; functionality since it\\'s format could be corrupted by an editor which will result in unexpected behavior.</p><p>Once you have a profile you can get it on the server like any other file. On WHM you can use the &quot;Upload Profile&quot; link on the profiles page to upload a profile from your computer or a URL from the internet.</p>};
our $info_icon = 'More Info';
our $hide_icon = 'Hide Info';
our $show_icon = 'Show Info';
our $docu_icon = 'More Info &#8593;';

sub pre_1134_version {
    return Cpanel::Version::Compare::compare( $Cpanel::Version::Tiny::VERSION_BUILD, '<', '11.34' );
}

sub pre_1140_version {
    return Cpanel::Version::Compare::compare( $Cpanel::Version::Tiny::VERSION_BUILD, '<', '11.40' );
}

sub perldoc {
    my ( $self, $easy, $file ) = @_;
    die 'Invalid perldoc arg' if !-f $file;

    $self->_header($easy);

    if ( eval { require Pod::Simple::HTML; 1; } ) {
        my $pod = Pod::Simple::HTML->new();
        $pod->{"html_css"} = "http://search.cpan.org/s/style.css";
        $pod->parse_from_file($file);
    }
    else {
        print "<p>You need to have 'Pod::Simple::HTML' installed before you can use this screen.</p>";
    }
}

#sub restore_backup {
#    my ($self, $easy) = @_;
#    $self->_header();
#    print "Backup restore UI coming soon.\n";
#    exit;
#}

sub print_to_screen_color {
    my ( $self, $easy, $color, $string ) = @_;

    if ( !$easy->{'_'}{'in-pretests'} && $easy->get_param('build') ) {
        chomp $string;
    }
    else {
        $string = Cpanel::CPAN::Text::InHTML::encode_plain($string);
    }

    $easy->{'allow_html'} = $easy->{'twiddler_uniq_id'} || rand() if !$easy->{'allow_html'};
    print qq{<span name="$easy->{'allow_html'}" style="font-weight: bold;color:$color;">$string</span><br/>\n};
}

sub _footer {
    my ( $self, $easy, $rawhtml, $tmpl_data ) = @_;
    return if !$easy->{'_'}{'_header'};    # only do it if we also did _header()
    return if $easy->{'_'}{'_footer'};     # only do it once
    $easy->{'_'}{'_footer'}++;             # tell it we've already done it once

    if ( !pre_1134_version() ) {

        # Close the pageContainer div
        # This is added as part of the WHM Imporvements project in 11.34.
        print qq{</div>\n};

        # Process _deffooter.tmpl which properly closes the html elements.

        # TODO: This can be replaced with Whostmgr::HTMLInterface::deffooter
        # at a later stage when Whostmgr::HTMLInterface::deffooter function
        # is modified to process _deffooter.tmpl template.
        my $template_args = {
            'template_file' => '_deffooter.tmpl',
        };

        if ($tmpl_data) {
            $template_args->{'data'} = $tmpl_data;
        }

        Cpanel::Template::process_template(
            'whostmgr',
            $template_args
        );
    }
    else {
        print "</div>\n </body>\n</html>";
    }
}

sub _header {
    my ( $self, $easy, $rawhtml ) = @_;
    return if $easy->{'_'}{'_header'};    # only do it once
    $easy->{'_'}{'_header'}++;            # tell it we've already done it once

    if ($rawhtml) {
        print "Content-type: text/html\n\n";    # starthtml() won't work here)

        print <<'END_HTML';
        <link href="/themes/x/master.css" rel="stylesheet" type="text/css">
        <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
        <!--[if gt IE 6]>
        <link rel="stylesheet" href="/themes/x/ie7.css">
        <![endif]-->
        <!--[if lt IE 7]>
        <link rel="stylesheet" href="/themes/x/ie6.css">
        <![endif]-->
        <link href="/legacy.css" type="text/css" rel="stylesheet">
        <link href="/themes/x/style.css" type="text/css" rel="stylesheet">
END_HTML
    }
    else {
        print "Content-type: text/html\n\n";
        Whostmgr::HTMLInterface::defheader( $easy->{'powered_by_line'}, '', '/cgi/easyapache.pl?action=_pre_cpanel_sync_screen' );
        print qq{<script type="text/javascript" src="/js/quicksupport.js"></script>};
        print qq{<script type="text/javascript" src="/js/popupbox.js"></script>};
        print qq{<script type="text/javascript" src="/cgi/easy_apache_ui/easy_apache.js"></script>};
    }

    if ( $easy->get_param('anchor') =~ m{ \A \w+ \z }xms ) {
        my $name = $easy->get_param('anchor');
        print <<"END_ANKR_CSS";
    <style type="text/css">
        #$name {
            background-color:#FFFFCC;
            border:1px solid #666666;
            margin-left:20px;
            padding:5px;
            width:500px;
        }
    </style>
END_ANKR_CSS
    }
    print qq{<link href="/cgi/easy_apache_ui/easy_apache.css" type="text/css" rel="stylesheet">};

    my $pageContainerCss = '';

    if ( pre_1134_version() ) {

        $pageContainerCss = <<"PAGE_CSS";
        #pageContainer {
            margin: 0 32px 20px 20px;
        }
PAGE_CSS
    }
    else {
        $pageContainerCss = <<"PAGE_CSS";

PAGE_CSS
    }

    print <<"END_STYLE";
    <style type="text/css">
        $pageContainerCss
    </style>
END_STYLE

    # Add pageContainer div as the container for the elements in the page.
    # This is added as part of the WHM Imporvements project in 11.34.
    print qq{<div id="pageContainer">};
}

sub pstconf_isbad {
    my ( $self, $easy, $rc, @text ) = @_;
    $easy->{'_'}{'restore_backup'}++ if !$easy->{'_'}{'prefs'}{'do_not_revert_on_conf_failure'};
    $easy->{'_'}{'build_ok_but_confgen_failed'}++;

    $easy->print_alert(@text) if @text;
    if ( $easy->{'_'}{'prefs'}{'do_not_revert_on_conf_failure'} ) {
        my ( $x, $y ) = ( $easy->{'_'}{'httpd.conf-template_generated'}, $easy->_get_main_httpd_conf() );
        if ( -e $x ) {
            Cpanel::FileUtils::safecopy( $x, $y )
              or $easy->print_alert_color( 'red', q{'[_1]' did not return true}, qq{safecopy($x, $y)} );
        }

        eval 'use Cpanel::CPAN::Text::InHTML ();';
        if ( !$@ ) {
            $easy->print_alert_color( 'red', Cpanel::CPAN::Text::InHTML::encode_plain( $easy->do_not_revert_on_conf_failure_text() ) );
        }
        else {
            $easy->print_alert( $easy->do_not_revert_on_conf_failure_text );
        }
    }
}

sub preconf_isbad {
    my ( $self, $easy, @text ) = @_;

    $self->_header($easy);
    $easy->print_alert_color( 'red', @text );
    my $url = $easy->_get_badconf_whm_url();

    print <<"BADCONF";
<p>In order to continue please manually rectify the problem or visit the <a href="$url">Apache Config Editor</a>.</p>
<p>Alternatively you may want to try to <a href="$ENV{'SCRIPT_NAME'}?build=1&profile=cpanel_default">build using the default profile</a>.
BADCONF

    $self->_footer();
    exit;
}

sub new {
    return bless {}, shift;
}

sub isa_ui {
    return 1;
}

sub setup {
    my ( $self, $easy ) = @_;

    # $easy->_cpanelsync();

    $easy->create_state_file();
    $easy->_create_backup();
}

sub get_param_hashref {
    my ( $self, $easy ) = @_;

    # Cpanel::Form::Param is already a blessed hash (IE object)
    my %unblessed_copy = %{ $easy->{'param_obj'} };
    return \%unblessed_copy;
}

sub cleanup {
    my ( $self, $easy ) = @_;
    return 1 if $easy->get_param('makecpphp');

    $easy->reinstate_restrictions_imposed_by_apache_make_install();
    $easy->unhide_imap_libraries() if ( $easy->{'_'}{'hide_imap_libraries'} );

    $easy->run_commands('pre-confgen-commands');

    $easy->post_httpd_conf_handler() if !$easy->{'_'}{'restore_backup'};    # no need to do it if we've already died
    $easy->_restore_backup_if_needed();

    $easy->archive_last_success_profile();

    $easy->run_commands('post-confgen-commands');

    $easy->update_runlog_entry( { 'status' => $easy->{'_'}{'restore_backup'} ? 0 : 1, } );

    $easy->report_errors();

    if ( !$easy->{'_'}{'restore_backup'} ) {
        $easy->hook_script('/usr/local/cpanel/scripts/posteasyapache');
    }
}

sub pid_file_failed {
    my ( $self, $easy, $pid_file_rc ) = @_;

    $self->_header($easy);

    if ( !defined $pid_file_rc ) {
        my $cur_run = <<'END_UNAVAIL';
<br />
Easyapache is currently running. You will need to wait for the other
instance to finishing running. If a build is currently running you will
need to wait for the build to complete before using this interface.
This process can take 30 minutes or longer depending on
what you've selected to build and the server's current state.
<br />
END_UNAVAIL
        print $easy->maketext($cur_run);
    }
    elsif ( $pid_file_rc == 0 ) {
        print $easy->maketext( 'Error reading or writing pidfile: [_1]', $! ) . "\n";
    }
    else {
        print $easy->maketext( q{Unknown/invalid pid_file_rc passed '[_1]'}, $pid_file_rc ) . "\n";
    }

    my $reload = $easy->maketext(q{Reload});
    print qq(<p align="center">[<a href="$ENV{'SCRIPT_NAME'}?1">$reload</a>]</p>\n);
}

sub output {
    my ( $self, $easy, $indent_level, @maketext ) = @_;

    my $log  = "\t" x int($indent_level) . $easy->maketext(@maketext) . "\n";
    my $html = '&nbsp; &nbsp; ' x int($indent_level) . $easy->maketext(@maketext) . "<br />\n";    # Text::InHTML-ify the maketext results ??

    if ( $maketext[0] eq q{-- Begin opt '[_1]' --} ) {
        $maketext[1] = Cpanel::Encoder::html_encode_str( $maketext[1] );
        my $new_ns_js = <<"END_JSA";
          <script type="text/javascript">
            <!--
              parent.document.getElementById("currentNamespace").innerHTML = "$maketext[1]";
            -->
          </script>
END_JSA
        $easy->print_to_screen($new_ns_js);
    }

    if ( $maketext[0] eq q{-- Begin step '[_1]' --} ) {
        $maketext[1] = Cpanel::Encoder::html_encode_str( $maketext[1] );
        my $new_ns_js = <<"END_JSC";
          <script type="text/javascript">
            <!--
              parent.document.getElementById("currentStep").innerHTML = "$maketext[1]";
            -->
          </script>
END_JSC
        $easy->print_to_screen($new_ns_js);
    }

    $easy->print_to_log($log);
    $easy->print_to_screen( $easy->{'ui_output_method_prints_plain_to_screen'} ? $log : $html );
}

sub print_to_screen {
    my ( $self, $easy, $string ) = @_;
    print $string;
}

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

    # use's main obj's lang_obj
    return {
        'output_ns' => 'Cpanel::CPAN::Text::Twiddler::HTML',

        # just use defaults or set these ?
        # 'start' => '',
        # 'text'  => '',
        # 'end'   => '',
    };
}

sub alert_over_last_twiddle {
    my ( $self, $easy, @maketext ) = @_;

    # need version for HTML driver ??
    # print "\b" x $easy->{'twiddler'}->get_longest() if $easy->{'twiddler'};

    $easy->print_alert(@maketext);

    if ( $maketext[0] eq q{Downloading '[_1]'} ) {
        my $string    = Cpanel::Encoder::html_encode_str( $easy->maketext(@maketext) );
        my $new_ns_js = <<"END_JSA";
          <script type="text/javascript">
            <!--
              parent.document.getElementById("currentNamespace").innerHTML = "$string";
            -->
          </script>
END_JSA
        $easy->print_to_screen($new_ns_js);
    }

    # $easy->print_to_screen("\n");
    # print ' ' x $easy->{'twiddler'}->get_longest() if $easy->{'twiddler'};
}

sub configure_profile {
    require Cpanel::Easy::Apache::UI::HTML::Config;
    goto &Cpanel::Easy::Apache::UI::HTML::Config::main;
}

sub install_profile {
    my ( $self, $easy, $profile ) = @_;
    $easy->check_apache_stopfile();

    $self->_header($easy);

    $easy->{'ui_output_method_prints_plain_to_screen'} = 1;
    $easy->{'allow_html'} = $easy->{'twiddler_uniq_id'} || rand() if !$easy->{'allow_html'};    # before build
    my ( $file, $spid ) = $easy->run_install_in_bg($profile);

    sleep(5);    #let the build get started

    my $zero = 'easyapache.pl';    # = $0; # $0 busted in 11.17.4-E20246, TODO: fix properly

    my $additional = '';
    for my $param (qw(skip-cpanelsync)) {
        $additional .= $easy->get_param($param) ? "&$param=1" : '';
    }
    $additional .= '&uref=' . $easy->{'allow_html'};

    print qq{<script type="text/javascript">var reportid = 'no report';</script>\n};
    my $iframe_src = "$zero?action=_tail_file_while_pid&pid=$spid&file=$file&build_id=$easy->{'time'}$additional";

    local $| = 1;

    print <<"END_HTML";
<style type="text/css">.container-size{ width: 75%; display: table; }</style>
<div class="minViewableWidth">
    [<a href="javascript:display_quickpopupbox('Profile Details','<iframe class=popupFrame src=easyapache.pl?skip-cpanelsync=1&action=show_all_features&profile=$easy->{'profile_main'} />')">Profile details</a>]
    [<a href="javascript:display_quickpopupbox('Profile Raw - $easy->{'profile_main'}','<iframe height=90% width=100% src=easyapache.pl?skip-cpanelsync=1&action=_human_readable&profile=$easy->{'profile_main'}&raw=1 />')">Raw profile</a>]
    [<a target="_blank" href="easyapache.pl?skip-cpanelsync=1&action=_human_readable&profile=$easy->{'profile_main'}&raw=1&download=1">Download profile</a>]
    [<a href="javascript:display_quickpopupbox('About Profiles','$layover_safe_profile_details')">About Profiles</a>]
    <h4>The entire verbose build output is available in $easy->{'log_file'}</h4>
    <div class="container-size">
        <div class="alert info">
            <span class="alertBody">
                If the server does not have enough memory to run the build via a browser (IE if you get "Out of memory" errors below) then you will have to do the build via command line with /usr/local/cpanel/scripts/easyapache.
            </span>
        </div>
    </div>
<!--<blockquote class="info_box" style="margin-left:0;">

    Additionally you might want to raise "The maximum memory a cPanel process can use before it is killed off" in the WebHostManager under Server Configuration &gt;&gt;
    <a target="_blank" href="../scripts2/tweaksettings">Tweak Settings</a> to at least the default 256 or even higher.

</blockquote>-->
END_HTML
    if ( $easy->{'proxied_whm_connection'} || $ENV{'HTTP_PROXY'} || $ENV{'HTTP_PROXIED'} ) {
        print <<END_PROXY_BLOCK;
<div class="container-size">
    <div class="alert info">
        <span class="alertBody">
            It appears that Apache is proxying your connection to the WebHost Manager. If the Build output window stops updating due to an Apache restart, click the "Refresh Output Window" button.
        </span>
    </div>
</div>

END_PROXY_BLOCK
    }

    # Start writing config required for running EA build profile javascript.
    my ( $curr_namespace, $curr_step, $build_status_id, $output_label_id, $chk_resize_id, $disable_scroll_id, $iframe_container_id ) = ( "currentNamespace", "currentStep", "apacheBuildStatus", "buildOutputLabel", "resizeBox", "disableScroll", "buildOutput" );
    my %js_config = (
        'currNamespace'     => "$curr_namespace",
        'currStep'          => "$curr_step",
        'buildStatusId'     => "$build_status_id",
        'outputLabelId'     => "$output_label_id",
        'chkResizeId'       => "$chk_resize_id",
        'disableScrollId'   => "$disable_scroll_id",
        'iframeContainerId' => "$iframe_container_id",
        'refreshUrl'        => "$iframe_src"
    );

    # Convert config hash to JSON which is understood by javascript.
    my $json_js_config = JSON::Syck::Dump( \%js_config );
    print <<"END_HTML";
<br />
<div>
  <div id="$curr_namespace">&nbsp;</div>
  <div id="$curr_step">&nbsp;</div>
  <div id="$build_status_id">
    <img src="/preloader.gif" />
  </div>
</div>
<br />

<div id="$output_label_id" style="font-size:14px;font-weight:bold;">
    Build output:
    [<a href="javascript:void(0);">Refresh Output Window</a>]
</div>
<p>
    <label for="$chk_resize_id">
        <input type="checkbox" id="$chk_resize_id" />
        Enlarge build output box
    </label>
    <br />
    <label for="chkDisableScroll">
        <span id="$disable_scroll_id">
            <input type="checkbox" ID="chkDisableScroll">
            Disable Auto Scroll (can not be re-enabled)
        </span>
    </label>
</p>

<div id="$iframe_container_id">
    <iframe id="apache_build_details" name="apache_build_details" src="$iframe_src"
            style="border: 1px solid #ffffff; margin: 0 auto; width: 700px; height: 400px;">
    </iframe>
</div>
<script type="text/javascript">
    // Did not use DOMReady or onload here. It is to make this work in IE8 too.
    //
    // Explanation: This is because of the way this page works.
    // This page has an iframe that keeps running for long time showing the updates.
    // So until the build process is done, technically the page is still loading.
    // Though DOMReady should be triggered when the DOM is ready, IE8 triggers it
    // only after the page loads. So, if that event is used to initiate the buildProfileMgr,
    // IE8 waits for the whole page to load to finish the initiation.
    // So none of the javascript works until the whole build process
    // completes(i.e. whole iframe finishes loading).
    //
    // TODO: Use DOMReady when support for IE8 is gone.

    var buildProfileMgr = null;
    buildProfileMgr = new CPANEL.ea.BuildProfileManager($json_js_config);
</script>
</div>
END_HTML

}

#### 'action=' actions ####

################### New TEMPLATE UTILITY methods ###################
sub show_all_features {
    my ( $self, $easy ) = @_;

    my $prof_name = $easy->get_param('profile') || '';

    my $profile_data_hr = $easy->get_all_features( profile => $prof_name );

    my $tmpl_args = {
        'template_file' => 'all_features_popup.tmpl',
        'data'          => {
            'feature_data' => $profile_data_hr,
        }
    };

    print "Content-type: text/html\n\n";
    Cpanel::Template::process_template(
        'whostmgr',
        $tmpl_args,
        { 'include_path' => "/var/cpanel/perl/easy/Cpanel/Easy/easy_apache_ui" }
    );

    exit;
}
##
# This method is used to process Upload Profile.
##
sub _profile_upload_tmpl {
    my ( $self, $easy ) = @_;

    my ( $is_submitted, $invalid_upload_type ) = ( 0, 0 );
    my %upload_submitted_result;

    print "Content-type: text/html\n\n";

    if ( $easy->get_param('upload') ) {

        # Upload profile template after submit
        $is_submitted = 1;

        my ( $yaml, $saveas, $url_fetch_error, $info_message, $is_success ) = ( '', '', '', '', 0 );

        if ( $easy->get_param('upload') eq 'file' ) {

            for my $fprm ( grep /file[-]/, $easy->{'param_obj'}->param() ) {

                next if $fprm !~ m{ [-] key \z}xms;

                if ( $fprm =~ m{\A file [-] (.*) [-] key \z}xms ) {
                    $saveas = $1;
                    my $tmpfile = $easy->{'param_obj'}->param( 'file-' . $saveas );

                    if ( $saveas =~ m/\\/ ) {
                        ($saveas) = reverse( split( /\\/, $saveas ) );
                    }

                    if ( -e $tmpfile ) {
                        $yaml = $easy->slurp_file_chomped( $tmpfile, { 'chomp' => 0 } );
                        unlink $tmpfile;
                        last;
                    }
                    else {
                        $saveas = '';
                    }
                }
            }
        }
        elsif ( $easy->get_param('upload') eq 'url' ) {
            my $url = $easy->get_param('upload_this');
            eval { require LWP::UserAgent; };

            if ($@) {
                $info_message = "Please install the LWP::UserAgent perl module.";
            }
            else {
                $url = Cpanel::Encoder::html_encode_str($url);
                my $ua = LWP::UserAgent->new;

                my $response = $ua->get($url);

                if ( $response->is_success() ) {
                    $yaml = $response->content();
                }
                else {
                    $url_fetch_error = $response->status_line();
                }

                $url =~ s{[?].*}{}g;
                ($saveas) = reverse split /\//, $url;
            }
        }
        else {
            $invalid_upload_type = 1;
        }

        my ( $error_message, $success_message ) = ( "", "" );
        if ( $yaml && $saveas ) {
            my $struct;
            eval {
                local $SIG{__WARN__};
                local $SIG{__DIE__};
                $struct = ( YAML::Syck::Load($yaml) )[0];
            };
            if ( !$struct ) {
                $error_message = "File does not appear to be YAML format.";
            }
            else {
                if ( ref $struct eq 'HASH' ) {
                    $saveas =~ s{\A cpanel [_] }{}xmsg;
                    $saveas =~ s{\..*}{};
                    if ( $saveas =~ m{ \A \w+ \z }xms ) {
                        my $profile = $easy->{'profile_custom_dir'} . '/' . $saveas . '.yaml';

                        Cpanel::FileUtils::touchfile($profile);
                        if ( -e $profile ) {
                            if ( $easy->save_profile( $struct, $profile ) ) {
                                $is_success      = 1;
                                $success_message = "Profile saved to '$profile'";
                            }
                            else {
                                $error_message = "Could not save profile";
                            }
                        }
                        else {
                            $error_message = "Could not create profile";
                        }
                    }
                    else {
                        $error_message = "Invalid file name";
                    }
                }
                else {
                    $error_message = "YAML is not a hashref";
                }
            }
        }
        else {
            $error_message = "Could not get contents and/or name";
        }

        %upload_submitted_result = (
            'invalidUploadType' => $invalid_upload_type,
            'infoMessage'       => $info_message,
            'isSuccess'         => $is_success,
            'urlFetchError'     => $url_fetch_error,
            'successMessage'    => $success_message,
            'errorMessage'      => $error_message,
        );
    }

    my $tmpl_args = {
        'template_file' => 'upload_profile.tmpl',
        'data'          => {
            'header'                => $easy->{'powered_by_line'},
            'uploadSubmittedResult' => \%upload_submitted_result,
            'isSubmitted'           => $is_submitted,
            'invalidUploadType'     => $invalid_upload_type,
        }
    };

    Cpanel::Template::process_template(
        'whostmgr',
        $tmpl_args,
        { 'include_path' => "/var/cpanel/perl/easy/Cpanel/Easy/easy_apache_ui" }
    );
    exit;
}
################### END New TEMPLATE UTILITY methods ###################

sub _last_run {
    my ( $self, $easy ) = @_;
    $self->_header( $easy, 1 );

    my $ns = $easy->get_param('ns');
    if ( !$easy->is_namespace($ns) ) {
        print "Invalid argument";
        $self->_footer();
        exit;
    }

    if ( exists $easy->{'last_failed'}{$ns} ) {
        my $msg = $easy->maketext( @{ $easy->{'last_failed'}{$ns}{'msg'} } );
        my $skipped_or_fatal = $easy->{'last_failed'}{$ns}{'fatal'} ? 'That was fatal to the build.' : "That just caused $ns to be skipped.";

        my ($build_id) = $easy->{'last_failed'}{'_buildlog_path'} =~ m{(\d+)$};

        my $log_path = -e $easy->{'last_failed'}{'_buildlog_path'} ? qq{The log for that build is here: <a target="_blank" href="easyapache.pl?action=_build_logs&build_id=$build_id">$easy->{'last_failed'}{'_buildlog_path'}</a>} : q{The log for that build no longer exists.};

        print <<"END_LASTTIME";
  <p>The last time <b>$ns</b> was run; step <b>$easy->{'last_failed'}{$ns}{'step'}</b> returned <b>$easy->{'last_failed'}{$ns}{'rc'}</b>.</p>
  <p>$skipped_or_fatal</p>
  <p>The message it gave was:<br /><b>$msg</p>
  <p>You might want to take that into consideration when choosing options and troubleshooting.</p>
  <p>$log_path</p>
END_LASTTIME

    }
    else {
        print "There were no registered issue with $ns";
    }
    $self->_footer();
    exit;
}

sub _archive_ui {
    my ( $self, $easy ) = @_;
    $self->_header($easy);

    print qq{<hr /><h3 style="font-size:24px;font-weight: bold;">Archive management</h3>\n};
    print qq{<div style="margin-left: 20px;">\n};

    print qq{<div class="info_box">Archive management WHM Interface will be available after CLI version is out of BETA status.<br />In the meantime you may use the BETA CLI interface: /usr/local/cpanel/scripts/easyapache --restore-archive</div>\n};

    print qq{<p align="center">[<a href="easyapache.pl?action=_pre_cpanel_sync_screen">Back</a>]</p>\n};
    print qq{</div>\n};    # end indent
    $self->_footer();
    exit;
}

sub _run_logs {
    my ( $self, $easy ) = @_;
    $self->_header($easy);
    print qq{<hr /><h3 style="font-size:24px;font-weight: bold;">Easy Apache Build History</h3>\n};
    print qq{<div style="margin-left: 20px;">\n};

    my $none = 0;
    if ( opendir my $runlog_dh, $easy->{'runlog_dir'} ) {
        my @runlogs = grep /build\.\d+ /xms, readdir($runlog_dh);
        closedir $runlog_dh;

        if (@runlogs) {
            for my $log (@runlogs) {

                # "$easy->{'log_dir'}/$log"
                # "$easy->{'runlog_dir'}/$log"

                my ($time) = reverse split /\./, $log;
                my $date = localtime($time);

                my $loglink = qq{[<a href="javascript:display_quickpopupbox('Profile Details','<iframe class=popupFrame src=easyapache.pl?skip-cpanelsync=1&action=show_all_features&profile=$easy->{'runlog_dir'}/$log />')">Profile</a>]};

                if ( -e "$easy->{'log_dir'}/$log" ) {
                    if ( -z "$easy->{'log_dir'}/$log" || -s "$easy->{'log_dir'}/$log" < 2600 ) {
                        unlink "$easy->{'log_dir'}/$log";
                    }
                    else {
                        $loglink .= qq{ [<a href="easyapache.pl?action=_build_logs&skip-cpanelsync=1&anchor=build_id$time#build_id$time">Build Log Page</a>]};
                    }
                }

                my $hr = $easy->deserialize("$easy->{'runlog_dir'}/$log");

                my $summary =
                  $hr->{'status'}
                  ? q{<span class="greenstatus">Pass</span>}
                  : q{<span class="errors">Fail</span>};

                my $more = '';

                if ( exists $hr->{'BuildAP Report Id'} ) {
                    $more .= qq{<h3>BuildAP Report Id : $hr->{'BuildAP Report Id'}</h3>};
                }

                if ( exists $hr->{'SIG'} ) {
                    $more .= q{<h3>The following signals were seen</h3>};
                    for my $sig ( sort keys %{ $hr->{'SIG'} } ) {
                        $more .= " $sig ($hr->{'SIG'}{$sig})<br />";
                    }
                }

                ## report

                if ($more) {
                    $summary = qq{<a href="javascript:display_quickpopupbox('Additional Details', '$more');">$summary</a>};
                }

                ## profile

                my $safe_yaml = YAML::Syck::Dump( $hr->{'profile'} );
                $safe_yaml =~ s{^---\s*}{};    # does not get properly encoded for some reason

                $safe_yaml = Cpanel::CPAN::MIME::Base64::Perl::encode_base64($safe_yaml);

                # TODO: readd this profile view && ad profile downloader using file name instead of YAML (too big for GET)
                # [<a href="javascript:display_quickpopupbox('Profile', '<iframe height=90% width=100% src=easyapache.pl?action=_human_readable&build_id=$time&skip-cpanelsync=1&profile_yaml=$safe_yaml></iframe>');">Profile</a>]
                print qq{<p id="build_id$time"><label name="build_id$time">$date ($time)</label> [$summary] $loglink</p>\n};
            }
        }
        else {
            $none++;
        }
    }
    else {
        $none++;
    }

    print qq{<p>There are no run logs to view</p>\n} if $none;
    print qq{<p align="center">[<a href="easyapache.pl?action=_pre_cpanel_sync_screen">Back</a>]</p>\n};
    print qq{</div>\n};    # end indent
    $self->_footer();
    exit;
}

sub _build_logs {
    my ( $self, $easy ) = @_;
    $self->_header($easy);
    print qq{<hr /><h3 style="font-size:24px;font-weight: bold;">Easy Apache Log Manager</h3>\n};
    print qq{<div style="margin-left: 20px;">\n};

    my $action = '_pre_cpanel_sync_screen';
    my ( $vol, $dir, $cur_file ) = File::Spec->splitpath( $easy->{'log_file'} );

    if ( $easy->get_param('delete') ) {
        $action = '_build_logs&skip-cpanelsync=1';
        my @remove = grep / \A \d+ \z /xms, $easy->get_param('build_id');
        if (@remove) {

            if ( !$easy->get_param('verify') ) {
                my $remove_hidden = '';
                for my $bid (@remove) {
                    $remove_hidden .= qq{      <input type="hidden" name="build_id" value="$bid" />\n};
                }

                print <<"END_VERIFY_DEL";
    <h3>Are you sure you want to delete those logs?</h3>
    <form action="easyapache.pl" method="post">
      <input type="hidden" name="skip-cpanelsync" value="1" />
      <input type="hidden" name="delete" value="1" />
      <input type="hidden" name="action" value="_build_logs" />
$remove_hidden
      <input type="submit" class="btn-primary primary default input-button" name="verify" value="Yes I am sure" />
    </form>
END_VERIFY_DEL
            }
            else {
                for my $bid (@remove) {
                    my $logfile = File::Spec->catfile( $dir, 'build.' . $bid );
                    if ( -e $logfile ) {
                        if ( unlink $logfile ) {
                            print "Log of Build ID '$bid' removed.<br />\n";
                        }
                        else {
                            print "Could not remove Log of Build ID '$bid': $!<br />";
                        }
                    }
                    else {
                        print "Log of Build ID '$bid' does not exist.<br />\n";
                    }
                }
            }
        }
        else {
            print "No valid Build IDs provided\n";
        }
    }
    else {
        if ( defined $easy->get_param('build_id') ) {
            $action = '_build_logs';

            if ( $easy->get_param('build_id') =~ m { \A \d+ \z }xms ) {
                my $logfile = File::Spec->catfile( $dir, 'build.' . $easy->get_param('build_id') );
                if ( -e $logfile ) {
                    my $time = $easy->get_param('build_id');
                    my $date = localtime($time);
                    print "<h3>[$logfile]<br />$date</h3><br />\n";

                    if ( -e "$easy->{'runlog_dir'}/build.$time" ) {
                        print qq{<p id="build_id$time">[<a href="easyapache.pl?action=_run_logs&skip-cpanelsync=1&anchor=build_id$time#build_id$time">Build History Page</a>]</p>\n};
                    }

                    if ( open my $log_fh, $logfile ) {
                        require Cpanel::CPAN::Text::InHTML;
                        while ( my $line = readline($log_fh) ) {
                            print Cpanel::CPAN::Text::InHTML::encode_plain($line);
                        }
                        close $log_fh;
                    }
                    else {
                        print "Could not open '$logfile': $!";
                    }
                }
                else {
                    print "No log for Build ID\n";
                }
            }
            else {
                print "Invalid Build ID\n";
            }
        }
        else {
            if ( opendir my $log_dh, $dir ) {
                print <<'END_DEL_FORM';
                    <form name="del_log" action="easyapache.pl" method="post">
                    <input type="hidden" name="skip-cpanelsync" value="1" />
                    <input type="hidden" name="delete" value="1" />
                    <input type="hidden" name="action" value="_build_logs" />
                    <div id="buildLogList">
                        <input type="checkbox" id="toggle_all_up" name="toggle_all_up" class="checkAll" />
                        <label for="toggle_all_up">
                            Check/Uncheck All
                        </label>
                        <br />
END_DEL_FORM

                my @files = grep / \A build [.] \d+ \z /xms, readdir($log_dh);
                for my $file ( sort @files ) {
                    next if $file eq $cur_file;

                    # remove empty or "initial" UI logs
                    my $path = File::Spec->catfile( $dir, $file );
                    if ( -z $path || -s $path < 2600 ) {
                        unlink File::Spec->catfile( $dir, $file );
                        next;
                    }

                    my ($time) = reverse split /\./, $file;
                    my $date = localtime($time);
                    print qq{<p id="build_id$time">
                                <input type="checkbox" id="chk_$time" name="build_id" value="$time" />
                                <label for="chk_$time" name="build_id$time">$date ($time)</label>
                                [<a href="easyapache.pl?action=_download_buildlog&build_id=$time">Download</a>]
                                [<a href="easyapache.pl?action=_build_logs&build_id=$time">View</a>]
                            </p>};
                }
                close $log_dh;
                print qq{<input type="checkbox" id="toggle_all_down" name="toggle_all_down" class="checkAll" />
                        <label for="toggle_all_down">Check/Uncheck All</label>
                        <br />
                    </div>};
                print qq{<input type="submit" class="btn-primary primary default input-button" value="Delete Checked" /></form>\n};
            }
            else {
                print "Could not open log dir: $!\n";
            }
        }
    }

    print qq{<p align="center">[<a href="easyapache.pl?action=$action">Back</a>]</p>\n};
    print qq{</div>\n};    # end indent

    print <<"END_JS";
        <script type="text/javascript">
          <!--
            EVENT.onDOMReady(function(){
                var config = {
                    logContainerId : "buildLogList",
                    checkAllClassName : "checkAll"
                };
                var buildLogMgr = new CPANEL.ea.BuildLogManager(config);
            });

          -->
        </script>
END_JS

    $self->_footer();
    exit;
}

sub _profile_upload {
    my ( $self, $easy ) = @_;
    $self->_header($easy);
    print qq{<hr /><h3 style="font-size:24px;font-weight: bold;">Profile Upload</h3>\n};
    print qq{<div style="margin-left: 20px;">\n};

    if ( $easy->get_param('upload') ) {
        my $yaml   = '';
        my $saveas = '';

        if ( $easy->get_param('upload') eq 'file' ) {

            for my $fprm ( grep /file[-]/, $easy->{'param_obj'}->param() ) {

                next if $fprm !~ m{ [-] key \z}xms;

                if ( $fprm =~ m{\A file [-] (.*) [-] key \z}xms ) {
                    $saveas = $1;
                    my $tmpfile = $easy->{'param_obj'}->param( 'file-' . $saveas );

                    if ( $saveas =~ m/\\/ ) {
                        print "[info] Buggy Internet Explorer based upload non standards compliance issue detected, auto handling...<br />\n";
                        ($saveas) = reverse( split( /\\/, $saveas ) );
                    }

                    if ( -e $tmpfile ) {
                        $yaml = $easy->slurp_file_chomped( $tmpfile, { 'chomp' => 0 } );
                        unlink $tmpfile;
                        last;
                    }
                    else {
                        $saveas = '';
                    }
                }
            }
        }
        elsif ( $easy->get_param('upload') eq 'url' ) {
            my $url = $easy->get_param('upload_this');
            eval { require LWP::UserAgent; };

            if ($@) {
                print "Please install the LWP::UserAgent perl module.";
            }
            else {
                $url = Cpanel::Encoder::html_encode_str($url);
                my $ua = LWP::UserAgent->new;

                my $response = $ua->get($url);

                if ( $response->is_success() ) {
                    $yaml = $response->content();
                }
                else {
                    print "<p>There was a problem fetching the URL:<br />\n" . $response->status_line() . "</p>\n";
                }

                $url =~ s{[?].*}{}g;
                ($saveas) = reverse split /\//, $url;
            }
        }
        else {
            print "Unknown upload type";
        }

        if ( $yaml && $saveas ) {
            my $struct;
            eval {
                local $SIG{__WARN__};
                local $SIG{__DIE__};
                $struct = ( YAML::Syck::Load($yaml) )[0];
            };
            if ( !$struct ) {
                print "File does not appear to be YAML format.";
            }
            else {
                if ( ref $struct eq 'HASH' ) {
                    $saveas =~ s{\A cpanel [_] }{}xmsg;
                    $saveas =~ s{\..*}{};
                    if ( $saveas =~ m{ \A \w+ \z }xms ) {
                        my $profile = $easy->{'profile_custom_dir'} . '/' . $saveas . '.yaml';

                        Cpanel::FileUtils::touchfile($profile);
                        if ( -e $profile ) {
                            if ( $easy->save_profile( $struct, $profile ) ) {
                                print "Profile saved to '$profile'";
                            }
                            else {
                                print "Could not save profile";
                            }
                        }
                        else {
                            print "Could not create profile";
                        }
                    }
                    else {
                        print "Invalid file name";
                    }
                }
                else {
                    print "YAML is not a hashref";
                }
            }
        }
        else {
            print "Could not get contents and/or name\n";
        }

        print qq{<p align="center">[<a href="easyapache.pl?action=_profile_upload&skip-cpanelsync=1">Upload another profile</a>]</p>\n};
    }
    else {
        print <<'END_UPLOAD_FORM';
<div class="info_box">
The URL or file should be a valid YAML Easy::Apache v3 profile. <br /><br />Missing values will be merged in from defaults. Unknown values may be ignored or cause warnings and errors.<br /><br />The file name to save the profile as on the server will be determined from the file or URL uploaded. Its the base file name with all extentions removed and any beginning 'cpanel_'s removed. For a URL the query string (including its '?') is also removed.
</div>
<br />
<form action="easyapache.pl" method="post">
  <input type="hidden" name="skip-cpanelsync" value="1" />
  <input type="hidden" name="action" value="_profile_upload" />
  <input type="hidden" name="upload" value="url" />
  <label for="upload_this">URL</label> 
  <input type="text" id="upload_this" name="upload_this" /> 
  <input type="submit" class="btn-primary primary default input-button" value="Upload URL" />
</form>
END_UPLOAD_FORM

        if ( defined $easy->{'param_obj'}->VERSION() ) {

            # trunk 17800 or later
            if ( $easy->{'param_obj'}->VERSION() > 0.1 ) {
                print <<'END_UPLOAD_FORM_X';
or
<form action="easyapache.pl" method="post" enctype="multipart/form-data">
  <input type="hidden" name="skip-cpanelsync" value="1" />
  <input type="hidden" name="action" value="_profile_upload" />
  <input type="hidden" name="upload" value="file" />
  <label for="upload_this_file">File</label> 
  <input type="file" id="upload_this_file" name="upload_this_file" /> 
  <input type="submit" class="btn-primary primary default input-button" value="Upload File" />
</form>
END_UPLOAD_FORM_X

            }
            else {
                print "Sorry, this version of Cpanel::Form::Param does not yet support file uploads.";
            }
        }
        else {
            print "Sorry, this version of Cpanel::Form::Param does not yet support file uploads.";
        }
    }

    print qq{<p align="center">[<a href="easyapache.pl?action=_pre_cpanel_sync_screen">Back</a>]</p>\n};

    print qq{</div>\n};    # end indent
    $self->_footer();
    exit;
}

sub _human_readable {
    my ( $self, $easy ) = @_;

    my $prof = $easy->get_param('profile') || '';

    $prof =~ s{ [.] yaml \z }{}xms;

    my $yaml = $easy->get_param('profile_yaml') || '';
    require Cpanel::CPAN::MIME::Base64::Perl;
    $yaml = Cpanel::CPAN::MIME::Base64::Perl::decode_base64($yaml) if $yaml;

    if ( $yaml || "$prof.yaml" eq $easy->{'profile_main'} || ( -e $prof && $prof =~ m{\A\Q$easy->{'runlog_dir'}\E/} ) || ( $prof =~ m{ \A \w+ \z }xms && -e "$easy->{'profile_custom_dir'}/$prof.yaml" ) ) {
        if ( $easy->get_param('raw') ) {
            my $long = $easy->determine_profile($prof);

            if ( $easy->get_param('download') ) {
                my ($short) = reverse split /\//, $long;
                $short = $easy->get_param('build_id') . '_run_log.yaml' if $yaml;
                print qq{Content-Disposition: attachment; filename="$short"\n};
            }
            print "Content-type: text/plain\n\n";

            if ($yaml) {
                print "---\n$yaml";
            }
            else {
                print $easy->slurp_file_chomped( $long, { 'chomp' => 0 } );
            }
        }
        else {
            $self->_header( $easy, 1 );

            if ($yaml) {
                print _get_profile_as_html( $easy, "---\n$yaml", 'Profile Used in Build ' . $easy->get_param('build_id') );
            }
            else {
                print _get_profile_as_html( $easy, $prof );
            }
        }
    }
    else {
        $self->_header( $easy, 1 );
        print "<p>Invalid profile specified</p>\n";
    }
    $self->_footer();
    exit;
}

sub _get_profile_as_html {
    my ( $easy, $profile, $profile_isyaml ) = @_;

    my $path = '';
    my $hr;
    if ( -e $profile && $profile =~ m{\A\Q$easy->{'runlog_dir'}\E/} ) {
        $path           = $profile;
        $hr             = $easy->deserialize($profile)->{'profile'};
        $profile_isyaml = 1;
    }
    else {
        $path = $profile_isyaml ? $profile_isyaml : $easy->determine_profile($profile);
    }

    if ( !defined $hr ) {
        $hr = $profile_isyaml ? eval { return ( YAML::Syck::Load($profile) )[0] } : $easy->deserialize($path);
    }

    my %apver = %{ $easy->_apache_versions() };
    $apver{ $hr->{'Apache'}{'version'} } =~ /^(\d+\.\d+)/;
    my $ap_short = $1;

    my $ap_optmod = '';
    for my $opt ( sort keys %{ $hr->{'Apache'}{'optmods'} } ) {
        my $opt_hr = $easy->get_easyconfig_hr_from_ns_variations( 'Cpanel::Easy::Apache::' . $opt );
        $ap_optmod .= _get_option_html_string( $opt_hr, $ap_short ) if $easy->get_ns_value_from_profile( 'Cpanel::Easy::Apache::' . $opt, $hr );
    }

    for my $non_php ( grep !/PHP/, @{ $easy->{'state_config'}{'include'} } ) {
        my $opt_hr = $easy->get_easyconfig_hr_from_ns_variations($non_php);
        $ap_optmod .= _get_option_html_string($opt_hr) if $easy->get_ns_value_from_profile( $non_php, $hr );
    }
    $ap_optmod .= qq{\n<tr><td colspan="3">&nbsp;</td></tr>\n};

    my $pretty = '5';
    my $par_ns = qq{Cpanel::Easy::PHP5};
    eval qq{use $par_ns;};
    if ( $easy->get_ns_value_from_profile( $par_ns, $hr ) ) {
        my %skip;

        for my $vr ( $par_ns->versions() ) {
            $skip{ $par_ns . "::$vr" }++;
            $pretty = "5.$vr" if $easy->get_ns_value_from_profile( $par_ns . "::$vr", $hr );
        }
        $pretty =~ s{\_}{\.}g;

        $ap_optmod .= qq{\n<tr><td colspan="3" style="font-weight: bold;">PHP $pretty</td></tr>\n};
        for my $ppopt ( grep /PHP5\::/, sort keys %{$hr} ) {
            next if exists $skip{$ppopt};
            my $opt_hr = $easy->get_easyconfig_hr_from_ns_variations($ppopt);
            $ap_optmod .= _get_option_html_string($opt_hr) if $easy->get_ns_value_from_profile( $ppopt, $hr );
        }
        $ap_optmod .= qq{\n<tr><td colspan="3">&nbsp;</td></tr>\n};
    }

    return <<"END_PROFILE";
[$path]<br />
<br />
<table border=0 width=450>
<tr><td colspan="3" style="font-weight: bold;">
Apache $apver{ $hr->{'Apache'}{'version'} }<br />
</td></tr>
$ap_optmod
</table>
END_PROFILE
}

sub _get_option_html_string {
    my $opt_hr   = shift;
    my $ap_short = shift;
    my $val      = '<tr><td align="center" valign="top">';
    if ( $opt_hr->{'url'} ) {
        my $url = $opt_hr->{'url'};
        $url =~ s/\[\% apache_uri_version \%\]/$ap_short/g if $ap_short;
        $val .= qq{[<a href="$url" target="_blank">$docu_icon</a>]};
    }
    $val .= '</td><td halign="right">';
    $val .= $opt_hr->{'name'};
    if ( $opt_hr->{'note'} ) {
        $val .= '</td><tr><td>&nbsp;</td><td style="font-style: italic;">' . $opt_hr->{'note'};
    }
    $val .= "</td></tr>\n";
    return $val;
}

sub _delete_profile {
    my ( $self, $easy ) = @_;

    $self->_header($easy);
    print qq{<hr /><h3 style="font-size:24px;font-weight: bold;">Delete Profile</h3>\n};
    print qq{<div style="margin-left: 20px;">\n};

    my $prof = $easy->get_param('del_profile') || '';
    my $back_link = qq{<p align="center">[<a href="easyapache.pl?action=_pre_cpanel_sync_screen">Back</a>]</p>\n};
    if ( $prof && $prof !~ m{^cpanel_} && $prof ne $easy->{'profile_main'} ) {
        if ( $easy->get_param('verified') ) {
            my $path = "$easy->{'profile_custom_dir'}/$prof.yaml";
            if ( -e $path ) {
                unlink $path or print "<p>Could not delete $path: $!</p>\n";
                print "Profile removed." if !-e $path;
            }
            else {
                print "<p>Profile does not exist</p>\n";
            }
            print $back_link;
        }
        else {
            my $prof_safe = Cpanel::Encoder::html_encode_str($prof);
            print <<"END_VERIFY";
            Are you sure you want to delete this profile?
            <form action="" method="post">
               <input type="hidden" name="verified" value="1" />
               <input type="hidden" name="action" value="_delete_profile" />
               <input type="hidden" name="del_profile" value="$prof_safe" />
               <input type="submit" class="btn-primary primary default input-button" value="Yes" />
            </form>
END_VERIFY
        }
    }
    else {
        print "<p>Invalid profile specified</p>\n";
        print $back_link;
    }

    print qq{</div>\n};    # end indent
    $self->_footer();
    exit;
}

sub _download_buildlog {
    my ( $self, $easy ) = @_;
    my $id = int( $easy->get_param('build_id') );

    if ( !$id ) {
        $self->_header($easy);
        print qq{<p class="errors">Invalid build log id.</p>\n};
    }
    elsif ( !-e '/usr/local/cpanel/logs/easy/apache/build.' . $id ) {
        $self->_header($easy);
        print qq{<p class="errors">No build log by that id.</p>\n};
    }
    elsif ( open my $log_fh, '<', '/usr/local/cpanel/logs/easy/apache/build.' . $id ) {
        print qq{Content-Disposition: attachment; filename="easy_apache_build.$id"\nContent-Type: text/plain;\n\n};
        while (<$log_fh>) {
            print;
        }
        close $log_fh;
    }
    else {
        $self->_header($easy);
        print qq{<p class="errors">Could not open log: $!</p>\n};
    }

    $self->_footer();
    exit;
}

sub hook_help {
    my ( $self, $easy ) = @_;

    $self->_header($easy);
    print qq{<div style="margin-left: 20px;">\n};
    if ( $easy->get_param('help') eq 'hooks-advanced' ) {
        print <<'END_HOOK';
<p>
If a hook script's exit status is checked to determine if it worked or not (Eg, like preeasyapache is handled), you can trigger "failure" by having it not exit cleanly.
</p><p>
For example, in /usr/local/cpanel/scripts/preeasyaapche you could set up a script that locked easyapache from building with this:
</p>
<pre><code>
#!/usr/bin/perl

my $file = '/etc/disable_easyapache_builds';
if (-e $file) {
   print "The admin has disabled me via $file\n";
   exit 1;
}
</code></pre>
<p>
Every hook script will get these argument passed to it in this order:
<ol>
 <li> easyapache version</li>
 <li> easyapache revision (not always an integer)</li>
 <li> apache version being built ( an empty string means we don't know yet, 0 means we are not building it, 2 part version string means it has not been built yet, 3 part version string means it was built)</li>
 <li> comma separated PHP versions being built ( an empty string means we don't know yet, 0 means we are not building it)</li>
 <li> all of your --hook-args values (if any) in the order they were specified</li>
</ol>
<pre><code>
#!/usr/bin/perl

my ($ea_version, $ea_revision, $apache, $php_csv, @hook_args) = @ARGV;

if ($ea_revision ne int($ea_revision)) {
    print "using a branch of some sort\n";
}

my @phps = split(/,/, $php_csv);

if( !$apache ) {
    if ( $apache == 0) {
        print "We are not building apache this run\n";
    }
    elsif ($apache eq '') {
        print "I must be /usr/local/cpanel/scripts/preeasyapache\n";
    }
}
</code></pre>
<p>
Every hook script will have an environment variable called 'ea3_params_yaml' that contains a YAML data structure of the parameters to easyapache.
</p><p>
To avoid conflicting with any flags the Cpanel::Easy framework uses or may use in the future, use --hook-args to pass custom data to the hook scripts.
</p>
<pre><code>
#!/usr/bin/perl

use YAML::Syck;
my $hr = YAMl::Syck::Load( $ENV{'ea3_params_yaml'} );

if ( exists $hr->{'hook-args'} && grep( /no notify/, @{ $hr->{'hook-args'} }) ) {
    print "Skipping user notification\n";
}
else {
    print "Notifying users...\n";
    notify_users($msg);
}
</code></pre>
END_HOOK

    }
    else {
        print <<"END_HOOK";
<p>
Below is a list of hook scripts easyapache calls if they exist and are executable.
</p><p>
Their output is sent to the screen and the log. The output has a before and after alert to visually separate it in the output.
</p><p>
Unless otherwise noted the exit value is ignored.
</p><pre>
<b>/usr/local/cpanel/scripts/preeasyapache</b>
   When: The very beginning of a build
   Exit: If it does not exit cleanly it will halt the build (IE exit(1);)
   Uses: (These are some general ideas you could implement how you see fit)
       - lock easyapache to keep it from building
       - alert users that apache is currently being updated
</pre><pre>
<b>/usr/local/cpanel/scripts/posteasyapache</b>
   When: The very end of a successful build
   Uses: (These are some general ideas you could implement how you see fit)
       - verify some customization is still working properly and alert someone if it is not
       - alert users that the apache update is complete
</pre><p>
Here are others that are called at the point their name suggests. They use before/after instead of pre/post to help indicate they relate to specific parts instead of the entire script.
 </p><p>
 <ul>
  <li>/usr/local/cpanel/scripts/before_apache_make</li>
  <li>/usr/local/cpanel/scripts/after_apache_make_install<br /> &nbsp; Hint: This is where you should apxs in other Apache modules</li>
  <li>/usr/local/cpanel/scripts/before_httpd_restart_tests</li>
  <li>/usr/local/cpanel/scripts/after_httpd_restart_tests</li>
</ul>
</p><p>
Use --skip-hooks to build without running any hooks (or the WHM equivalent found in EasyApache's 'Help' section).
</p><p>
For more details see <a href="?help=hooks-advanced">Advanced Hook Script Help</a>
</p>
END_HOOK

    }
    print "</div>\n";    # end <div style="margin-left: 20px;">

    $self->_footer();
    exit;
}

sub quickreference_guide {
    my ( $self, $easy ) = @_;

    my $do       = 'easyapache.pl?action=quickreference_guide&skip-cpanelsync=1&do';
    my $includes = q{<a class="link_standout" href="javascript:display_quickpopupbox('Includes', 'Includes are much easier to work with and can be managed via WHM <a href=../scripts2/editinclude>here</a>.')">Includes</a>};
    my $content  = [
        qq{
        <h3>EasyApache Quick Reference guide</h3>
        <p><a href="$do=1">How do I make sure my manual httpd.conf edits are preserved?</a></p>
        <p><a href="$do=2">How can I get custom modules into the EasyApache build?</a></p>
        <hr /><p>[<a href="easyapache.pl">Go back to the EasyApache</a>]</p>
        },
        qq{
<h3>How do I make sure my manual httpd.conf edits are preserved?</h3>
<p><a  class="link_standout" href="javascript:display_quickpopupbox('Why do I even need to ask this question?','<iframe height=80% width=100% src=$do=3 />')">Why do I even need to ask this question?</a></p>

<p>If your needs can possibly be handled via $includes it is highly recommended that you use them instead of manual edits.</p>
<p>That said, let's begin:</p>

<h4> 1. First we edit Apache's main configuration file</h4>
By way of example, lets say we want to change the TimeOut directive. First open it in a text editor:
<pre class="terminal"><code>
myserver# <b>vi /usr/local/apache/conf/httpd.conf</b>
...
<span style="border: 1px solid">T</span>imeOut 150
...
</code></pre>

Simply edit the value:
<pre class="terminal"><code>
myserver# <b>vi /usr/local/apache/conf/httpd.conf</b>
...
TimeOut 250<span style="border: 1px solid">&nbsp;</span>
...
</code></pre>

Then save the file.

<h4> 2. Next we must let cPanel's httpd.conf datastore know about our change so it can be preserved</h4>

<!--
If your edit was not in a VirtualHost section run this command to get the main datastore updated:
<pre class="terminal"><code>
myserver# <b>/usr/local/cpanel/bin/apache_conf_distiller --update --main</b>
Distilled successfully
myserver#
</code></pre>

If your edit was in a VirtualHost section run this command to get the VirtualHost "userdata" data updated.:
-->
To update any relevant datastores run this:
<pre class="terminal"><code>
myserver# <b>/usr/local/cpanel/bin/apache_conf_distiller --update</b>
Distilled successfully
myserver#
</code></pre>

Assuming there are no errors in that output that need addressed we can move on.

<h4> 3. Now we should verify the change will be preserved when cPanel rebuilds httpd.conf</h4>

To do that, first we rebuild it:
<pre class="terminal"><code>
myserver# <b>/usr/local/cpanel/scripts/rebuildhttpdconf</b>
Succeeded
myserver#
</code></pre>

Assuming there are no errors in that output that need addressed lets check that our change is still in there:
<pre class="terminal"><code>
myserver# <b>grep TimeOut /usr/local/apache/conf/httpd.conf</b>
TimeOut 250
myserver#
</code></pre>

<h4> 4. My edit was not preserved when I rebuilt httpd.conf!</h4>
If this happens it means the change could not be preserved. You will have to use $includes at this point.
        <hr /><p>[<a href="$do=0">Go back to main Quick Reference screen</a>]</p>
        },
        qq{
        <h3>How can I get custom modules into the EasyApache build?</h3>
        <p><a  class="link_standout" href="javascript:display_quickpopupbox('Why do I even need to ask this question?','<iframe height=80% width=100% src=$do=4 />')">Why do I even need to ask this question?</a></p>
        <p>There are basically 4 ways of doing this depending on what it is you are trying to accomplish:</p>
        <p>&nbsp; &nbsp; <i>These links open in a new window</i></p>
        <ul>
            <li><a target="_blank" href="http://go.cpanel.net/eaenv">Modifying Environment Variables</a></li>
            <li><a target="_blank" href="http://go.cpanel.net/eaconfig">Adding your own flags to various configure calls</a></li>
            <li><a target="_blank" href="?help=hooks">Hook Scripts</a></li>
            <li><a target="_blank" href="http://go.cpanel.net/customea">Custom Option Modules</a></li><!-- change URL to WHM manager when available -->
        </ul>
        <!-- <p>You can find out in the section 'Customizing the Build' (starting on page 13) of <a target="_blank" href="http://www.cpanel.net/conference/08/files/EA3Build.pdf#page=13">this PDF</a>.</p> -->
        <hr /><p>[<a href="$do=0">Go back to main Quick Reference screen</a>]</p>
        },
        qq{
cPanel facilitates building an Apache 2.2, or 2.4 format httpd.conf so that you can choose which version of Apache you want to run.
<br /><br />
This flexibility and the differences in Apache versions means that the httpd.conf file can no longer be used as the datastore. cPanel supports the different versions by building httpd.conf from a seperate datastore.
<br /><br />
That means manual edits will be lost the next time it is built by cPanel. (IE because the cPanel system does not know about your changes...) "lost", that is, unless you tell cPanel about those changes. How to do register your changes with cPanel is what page shows you how to do.
        },
        qq{
For Apache's install to work correctly /usr/local/apache must be cleaned up first. This includes backing up and removing the libexec and modules directories.
<br/ ><br/ >
The backed up module may not work with the new Apache. For this and other reasons you should use a hook script or more preferably custom option modules to rebuild the module against the new Apache.
<br/><br/>
Tip: apxs can add the LoadModule to the main httpd.conf for you. Then you can use &lt;IfModule&gt; sections in your includes if you wish.
<br /><br />
Custom option modules are the preferred way to build modules as they are more easily provisioned and reusable and take advantage of EasyApache's framework (including UI logic) whereas a hook script is just executed. Another example advantage is that you can enable and disable it with a checkbox in the UI instead of editing code.
        },
    ];

    $do = abs( int( $easy->get_param('do') ) );
    $do = 0 if ( $do + 1 ) > @{$content};
    $self->_header( $easy, $do == 3 || $do == 4 ? 1 : 0 );
    my $style = $do == 3 || $do == 4 ? '' : q{ style="margin-left: 20px;"};
    print <<"END_QS";

<div$style>
$content->[$do]
</div>
END_QS

    $self->_footer();
    exit;
}

sub _tail_file_while_pid {
    my ( $self, $easy ) = @_;

    $|++;
    print "Content-type: text/html\n\n";
    print q{<html>},                                                                                                                                          "\n";
    print q{<body style='font-family: "Courier New", Courier, monospace; font-size: 11px; background: #222222; color: #ffffff; padding: 5px 5px 10px 5px;'>}, "\n";
    print q{<div id='content'>},                                                                                                                              "\n";
    print "If the browser window is closed or stopped the build will continue in the background.<br />\n";
    print "The build output should start shortly...<br /><hr /><br />\n";
    my $file     = $easy->get_param('file');
    my $pid      = $easy->get_param('pid');
    my $build_id = $easy->get_param('build_id');

    require Cpanel::CPAN::Text::InHTML;

    eval {
        $easy->tail_file_while_pid(
            {
                'file'  => $file,
                'pid'   => $pid,
                'print' => sub {
                    my ( $self, $line ) = @_;

                    $self->{'no_encode'} = 1 if $line =~ m{<script type="text/javascript">};    # until 'safe HTML' marker system is implemented on JS tags since functionality relies on JS

                    my $twid_id = $easy->get_param('uref') || '';

                    if ( ( $twid_id && $line =~ m{$twid_id} ) || ( $line =~ m{</script>} || $line =~ m{</span>} ) ) {
                        $self->{'no_encode'} = $line =~ m{</script>} || $line =~ m{</span>} ? 0 : 1;
                        return $line . '<br />';
                    }

                    my $return = $self->{'no_encode'} ? $line : Cpanel::CPAN::Text::InHTML::encode_plain($line);
                    $self->{'no_encode'} = 0 if $line =~ m{</script>} || $line =~ m{</span>};    #  needs handled better...
                    return $return;
                },
            }
        );
    };

    if ($@) {
        $easy->print_alert( q{Tail of '[_1]' for PID '[_2]' failed: '[_3]'}, Cpanel::Encoder::html_encode_str($file), Cpanel::Encoder::html_encode_str($pid), Cpanel::Encoder::html_encode_str($@), );
    }
    my $short_desc = "Build id: $build_id.  Report id: ' + reportid + '";
    my $longdesc   = '\\\\n\\\\n\\\\n\\\\n' . "--" . '\\\\n' . "Build id: $build_id. " . '\\\\n\\\\n' . "Report id: ' + reportid + '";

    my ( $img, $txt ) =
      !-e $file
      . '.had_error'
      ? (
        '/preloader-done.gif',
        q{<div style=\"font-size:20px;color: #339933; font-weight: 900;\">Build Complete!</div><br /><div style=\"color: #ff0000; font-weight: 900;\">You can change how PHP is configured <a href=\"../scripts2/phpandsuexecconf\">here</a>.</div><br />}
      )
      : (
        '/preloader-red-done.gif',
        'An Error has occurred, please make sure that apache is running and restartable. <span style=\"color: #ff0000; font-weight: 900;\">Feel free to submit a support ticket <a onClick=\"return do_quick_support(\'easyapache\',\'3\',\'Build Failure\',\'buildid\',\''
          . $build_id
          . '\',\'file\',\''
          . $file
          . '\',\'subject\',\'[easyapache3] Build Failure: '
          . $short_desc
          . '\',\'body\',\''
          . $longdesc
          . '\');\" target=\"_blank\" href=\"https://tickets.cpanel.net/submit/index.cgi?reqtype=tickets\">here</a>.</span>'
      );

    $short_desc = "Build id: $build_id.  Report id: ' + parent.reportid + '";
    $longdesc   = '\n\n\n\n' . "--" . '\n' . "Build id: $build_id. " . '\n\n' . "Report id: ' + parent.reportid + '";

    my $zero = 'easyapache.pl';    # = $0; # $0 busted in 11.17.4-E20246, TODO: fix properly

    my ( $is_ensurepkg_error, $show_support_popup ) = ( 0, 0 );

    if ( -e $file . '.had_error' ) {
        if ( -e $file . '.ensurepkgs_error' ) {

            # Set the ensure pkg error flag.
            $is_ensurepkg_error = 1;

        }
        elsif ( !-e $file . '.rawopts_used' && !-e $file . '.rawenv_used' ) {

            # Set the show support popup flag.
            $show_support_popup = 1;

        }
    }

    print <<"END_JSB";
      <script type="text/javascript">
        <!--
            var isEnsurepkgError = $is_ensurepkg_error,
                showSupportPopup = $show_support_popup;

            // Using window.onload because this Iframe does not have
            // YAHOO. And it did not make sense to load YUI just for
            // using DOMReady.

            window.onload = function(){
                // Run script needed after build process.
                if(isEnsurepkgError){
                    if (parent['display_quickpopupbox']) {
                        parent.display_quickpopupbox('Ensurepkgs Error', '<html><body>Your OS software management system does not appear to be functioning correctly.<br /><br />Please visit <a href="http://go.cpanel.net/eaerror" target="_blank">http://go.cpanel.net/eaerror</a> for help with this error.</body></html>');
                    }
                } else if(showSupportPopup){
                    parent.do_quick_support('easyapache','3','Build Failure','buildid','$build_id','file','$file','subject','[easyapache3] Build Failure: $short_desc','body','$longdesc');
                } else {
                    if (parent['display_quickpopupbox']) {
                        parent.display_quickpopupbox('Configure Suexec and PHP','<iframe height=90% width=100% src=../scripts2/phpandsuexecconf?popupbox=1>');
                    }
                }

                var buildMgr = parent.buildProfileMgr;
                if(buildMgr !== null){
                    var outputTxt = "Build output: [<a target=\\"_blank\\" href=\\"$zero?action=_download_buildlog&build_id=$build_id\\">Download Log</a>]";
                    buildMgr.updateBuildOutput(outputTxt);

                    var statusTxt = "<img src=\\"$img\\" /><br />$txt";
                    buildMgr.updateBuildStatus(statusTxt);

                    buildMgr.clearInfoVariables();
                    buildMgr.removeAutoScroll();
                }
            };
        // -->
      </script>
END_JSB

    # End the html in apacheBuildDetails iframe
    print " </div>\n</body>\n</html>";
    exit;
}

sub httpd_whm_proxy_helper {
    my $self    = shift;
    my $easy    = shift;
    my $args_hr = shift;
    return 0 unless defined $args_hr->{'action'};
    if ( $args_hr->{'action'} eq 'return_is_proxy_boolean' ) {
        if ( $easy->{'proxied_whm_connection'} || $ENV{'HTTP_PROXY'} || $ENV{'HTTP_PROXIED'} ) {
            return 1;
        }
        else {
            return;
        }
    }
    if ( $args_hr->{'action'} eq 'print_message' ) {
        $easy->print_alert('Apache is restarting and it appears that you are using Apache to proxy your connection to the WebHost Manager.  If the Build Output window stops updating, click the "Refresh Output Window" link.');
    }
}

1;
