package Cpanel::Easy::Utils::Report;

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

use strict;
use warnings;
no warnings qw(redefine);
use Cpanel::SafeRun ();
use Cpanel::Rand    ();

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

    if ( exists $self->{'last_failed_file'} ) {
        if ( exists $self->{'failed_opt_mod'} && ref $self->{'failed_opt_mod'} eq 'HASH' && keys %{ $self->{'failed_opt_mod'} } ) {
            $self->{'failed_opt_mod'}{'_buildlog_path'} = $self->{'log_file'};
            $self->serialize( $self->{'last_failed_file'}, $self->{'failed_opt_mod'} );
        }
        else {
            unlink $self->{'last_failed_file'};
        }
    }

    return if !$self->{'_'}{'prefs'}{'notify_cpanel'};

    require Cpanel::CPAN::YAML::Tiny;
    require Cpanel::CPAN::Text::InHTML;

    my $status = keys %{ $self->{'_'}{'error'} } ? 0 : 1;
    my $report = $status ? 'Build Completed Ok' : '';

    $self->print_to_log_and_screen( $self->maketext(q{Compiling report...}) );

  WHERE:
    for my $where ( @{ $self->{'_'}{'error_order'} } ) {
      WHAT:
        for my $what (
            sort { $self->{'_'}{'error'}{$where}{$a}{'time'} <=> $self->{'_'}{'error'}{$where}{$b}{'time'} }
            keys %{ $self->{'_'}{'error'}{$where} }
          ) {

            my $pretty_time = localtime( $self->{'_'}{'error'}{$where}{$what}{'time'} );

            $report .= <<"END_PRE";
[ What  ] $what
[ Where ] $where
[ When  ] $pretty_time ( $self->{'_'}{'error'}{ $where }{ $what }{'time'} )
[ RC    ] $self->{'_'}{'error'}{ $where }{ $what }{'rc'}
[ text  ]

$self->{'_'}{'error'}{ $where }{ $what }{'text'}

[ /text ]
END_PRE
        }
    }

    {
        use bytes;
        $self->print_to_log_and_screen( $self->maketext(q{Sending report. As some of the attached files may be quite large, this could take a few minutes. Thanks for your patience.}) );
    }

    if ($report) {
        $self->_send_report( $status, $report );
    }

    # else {
    # how could they have gotten here and $report be empty ?
    # }

    $self->print_to_log_and_screen( $self->maketext(q{Report processed.}) );

    return 1;
}

sub _send_report {
    my ( $self, $status, $report ) = @_;

    require HTTP::Tiny;
    require Cpanel::DIp;

    my $os = $self->{'getos'};
    my ( $osver, $es ) = @{ $self->{'getreleaseversion'} };

    if ( defined $es ) {
        $os .= '_enterprise' if $es == 1;
        $os =
            $es == 2 ? 'centos'
          : $es == 3 ? 'whitebox'
          : $es == 4 ? 'caos'
          :            $os;
    }

    my $envtype = '';
    if ( open my $et_fh, '<', '/var/cpanel/envtype' ) {
        $envtype = do { local $/; <$et_fh> };
        close $et_fh;
    }
    else {
        $envtype = $!;
    }

    require Cpanel::Version;
    my $whmversion = ( Cpanel::Version->can('get_version_full') ) ? Cpanel::Version::get_version_full() : Cpanel::Version::getversion();
    $whmversion ||= 'unknown';

    my $distro = "$os\_$osver ($self->{'cpu_bits'} bit) [envtype: $envtype]";

    my $targz_guts = '';
    my $attached   = '';

    my $tmp_file = '';
    if ( $self->{'_'}{'debug_info_for_report'} ) {
        $tmp_file = Cpanel::Rand::gettmpfile();
        if ( open my $tmp_fh, '>', $tmp_file ) {
            print {$tmp_fh} $self->{'_'}{'debug_info_for_report'};
            close $tmp_fh;
            push @{ $self->{'attach_files_to_report'} }, $tmp_file;
        }
        else {
            $self->print_alert( q{Could not open() file '[_1]' for writing: [_2]}, $tmp_file, $! );
        }
    }

    if ( @{ $self->{'attach_files_to_report'} } ) {

        my %uniq;
        @{ $self->{'attach_files_to_report'} } = map { $uniq{$_}++ == 0 ? $_ : () } @{ $self->{'attach_files_to_report'} };

        $attached = join ',', @{ $self->{'attach_files_to_report'} };    # not in eval so we can see if its supposed to have files and doesn't
        local $SIG{'ALRM'} = sub {
            $self->print_alert( q{Creating tarball of '[_1]' timed out. No tarball will be sent with report.}, join( ', ', grep { -e $_ } @{ $self->{'attach_files_to_report'} } ), );
            $targz_guts = '';
        };

        my $remaining = alarm(360);
        my $started   = time;

        my $attached  = $self->{'attach_files_to_report'};
        my $log_regex = qr{.*/build[.]\d{8,}$};
        my @logfiles  = grep { /$log_regex/ } @{$attached};
        @{$attached} = grep { !/$log_regex/ } @{$attached};
        my @sanitized;
        for my $log (@logfiles) {
            my $log_copy = "$log.cpanel";
            push @sanitized, $log_copy if $self->sanitize_log( $log, $log_copy );
        }

        push @{$attached}, @sanitized;

        eval {
            require Cpanel::CPAN::MIME::Base64::Perl;
            $targz_guts = Cpanel::CPAN::MIME::Base64::Perl::encode_base64( scalar( Cpanel::SafeRun::saferunnoerror( 'tar', 'cz', '-f', '-', grep { -e $_ } @{ $self->{'attach_files_to_report'} } ) ) );
        };

        if ( !$@ && $tmp_file ) {
            unlink $tmp_file;
        }

        unlink @sanitized if @sanitized;

        my $stopped = time;
        if ($remaining) {
            $remaining -= $stopped - $started;
        }
        $remaining = 0 if $remaining < 1;
        alarm($remaining);    #if another alarm was running then reinstate it, if not then cancel alarm
    }

    my $query = {
        'host'            => $self->{'hostname'},
        'ip'              => Cpanel::DIp::getmainserverip() || '',
        'osver'           => $distro,
        'bstatus'         => $status,
        'blog'            => $report,
        'ea_vers'         => $self->{'version'},
        'ea_rev'          => $self->{'revision'},
        'ea_ui'           => ref( $self->{'ui_obj'} ),               # or reverse( split( /::/, ref($self->{'ui_obj'}) ) ),
        'tarball'         => $targz_guts,
        'manifest'        => $attached,
        'whmversion'      => $whmversion,
        'conf_gen_failed' => $self->{'conf_gen_failed'} ? 1 : 0,
        'profile_revision' => $self->{'working_profile'}{'_meta'}{'revision'} || 0,
    };

    my $report_host = $self->{'report_host'} || 'buildap.cpanel.net';
    my $report_uri  = $self->{'report_uri'}  || 'buildap-submit.pl';
    my $combined_uri = 'https://' . $report_host . '/' . $report_uri;

    my $http = HTTP::Tiny->new( verify_SSL => 1 );
    my $response = $http->post_form( $combined_uri, $query );
    my $output = $response->{'content'};

    my %runlog = ( 'report' => $report, );

    if ($output) {
        if ( $output =~ m{(BuildAP Report Id):\s+(\d+)} ) {
            my ( $name, $number ) = ( $1, $2 );
            $self->print_alert_color( 'green', q{If you  want to create a support ticket with cPanel regarding this please reference '[_1]': '[_2]'}, $name, $number );
            $runlog{$name} = $number;

            # todo have UI handle this properly
            if ( ref $self->{'ui_obj'} eq 'Cpanel::Easy::Apache::UI::HTML' ) {
                $self->print_to_screen(qq{<script type="text/javascript">\nparent.reportid='$number';\n</script>});
            }
        }

        if ( $output =~ m{Error: (.*)} ) {
            $self->print_alert_color( 'red', q{An error has occured with this request: '[_1]'}, $1, );
        }
    }

    $self->update_runlog_entry( \%runlog );
}

sub sanitize_log {
    my ( $self, $inlog, $outlog ) = @_;

    my ( $infh, $outfh );
    unless ( open $infh, '<', $inlog ) {
        $self->print_alert_color( 'red', q{Could not open '[_1]' for reading: [_2]}, $inlog, $! );
        return;
    }

    unless ( open $outfh, '>', $outlog ) {
        $self->print_alert_color( 'red', q{Could not open '[_1]' for writing: [_2]}, $outlog, $! );
        close $infh;
        return;
    }

    my $in_section;

    while (<$infh>) {
        s/^(skipping cpanel user) \w+/$1 *****/i;

        if (/^\s*--\s*(Begin|End)\b.*\bFileprotect\b/) {
            $in_section = $1 eq "Begin" ? 1 : 0;
        }

        if ($in_section) {
            s{Setting\s+permissions\s+for(.*)Done}
             {
                my @users = split m{\W+}, $1;
                @users = grep { defined && /\w/ } @users;
                my $nusers =  @users;
                "Setting permissions for ... ( *** ... $nusers users ... *** ) ... Done"
             }e;
        }

        print {$outfh} $_;
    }

    close $infh;
    close $outfh;

    return 1;
}

1;
