Viewing File: /usr/local/cpanel/whostmgr/docroot/cgi/cpaddons.pl

#!/usr/local/cpanel/3rdparty/bin/perl

# cpanel - whostmgr/docroot/cgi/cpaddons.pl        Copyright 2022 cPanel, L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

=head1 DESCRIPTION

Manage cPanel&WHM cPaddons

We have B<deprecated> this interface in cPanel & WHM version 104 and plan to remove it in future versions.
For more information, read our L<cPanel Deprecation Plan|https://docs.cpanel.net/knowledge-base/cpanel-product/cpanel-deprecation-plan/>
documentation.

=head1 Functions

=cut

use strict;
## no critic qw(TestingAndDebugging::RequireUseWarnings) -- This file is not warnings-safe.

BEGIN { unshift @INC, '/usr/local/cpanel', '/usr/local/cpanel/whostmgr/docroot/cgi', '/usr/local/cpanel/cpaddons'; }

use CGI;
use IPC::Open3 ();
use Carp       ();

use Time::HiRes ();
my $debug      = CGI::param('debug') ? 1 : 0;
my $start_page = [ Time::HiRes::gettimeofday() ] if $debug;

use Cpanel::Config::Sources        ();
use Cpanel::cPAddons::Filter       ();
use Cpanel::cPAddons::LegacyNaming ();
use Cpanel::OS                     ();
use Cpanel::SafeRun::Simple        ();
use Cpanel::Server::Type           ();
use Cpanel::Encoder::Tiny          ();
use Cpanel::HttpRequest            ();
use Cpanel::PipeHandler            ();
use Cpanel::StringFunc::Match      ();
use Cpanel::StringFunc::Trim       ();
use Cpanel::Template               ();
use Whostmgr::ACLS                 ();
use Whostmgr::Cpaddon::Conf        ();
use Whostmgr::Cpaddon::Signatures  ();
use Whostmgr::Addons::Manager      ();

if ( !Cpanel::OS::supports_cpaddons() || -e q[/var/cpanel/cpaddons.disabled] ) {
    my $msg = "cPAddons are disabled on this server";
    if ( !-t STDIN ) {
        print "Content-type: text/html\r\n\r\n";
        print_header();
        print div_warning($msg);
    }
    else {
        print $msg;
    }
    exit 0;
}

chdir('/usr/local/cpanel') || die "Could not chdir /usr/local/cpanel: $!";

# CGI::param called in list context can lead to vulnerabilities.
#   http://blog.gerv.net/2014.10/new-class-of-vulnerability-in-perl-web-applications
# We are not using the list to populate a hash, disable the warning
$CGI::LIST_CONTEXT_WARN = $CGI::LIST_CONTEXT_WARN = 0;    # no warnings once

local $| = 1;

my $action = CGI::param('action');
my $nohtml;

# The nohtml flag is currently only supported on the update action.

if ( $action eq 'update-nohtml' ) {
    $action = 'update';
    $nohtml = 1;
}

my ( $br, $output_handler );

my $TEMPLATE_DIRECTORY   = 'cpaddons/partials';
my $TEMPLATE_APPLICATION = 'whostmgr';

if ($nohtml) {
    if ( !-t STDIN ) {
        print "Content-type: text/plain\r\n\r\n";
    }

    $br = "\n";
    require Cpanel::Output::Template;
    $output_handler = Cpanel::Output::Template->new(
        template_directory => $TEMPLATE_DIRECTORY . "/text",
        template_extension => '.tmpl',
        application        => $TEMPLATE_APPLICATION,
        break              => $br,
    );

    require Cpanel::Output::Formatted::Terminal;
    $Cpanel::SysPkgs::OUTPUT_OBJ_SINGLETON = Cpanel::Output::Formatted::Terminal->new();

}
else {
    print "Content-type: text/html\r\n\r\n";
    print_header();

    $br = "<br />\n";
    require Cpanel::Output::Template;
    $output_handler = Cpanel::Output::Template->new(
        template_directory => $TEMPLATE_DIRECTORY . "/html",
        template_extension => '.tmpl',
        application        => $TEMPLATE_APPLICATION,
        break              => $br,
        expand_linefeeds   => 1,
    );

    # Setup the output formatter for the YUM system.
    require Cpanel::Output::Formatted::HTML;
    $Cpanel::SysPkgs::OUTPUT_OBJ_SINGLETON = Cpanel::Output::Formatted::HTML->new();
}

#Allows mainCommand features to display in left nav. To ensure that ACL init happens for all the pages that use _defheader so that Left navigation and ACL checks work.
Whostmgr::ACLS::init_acls();

if ( !Whostmgr::ACLS::hasroot() ) {
    if ( !-t STDIN && !$nohtml ) {
        print_output( 'Permission denied', 'error', 'permission-denied-error' );
        print_footer();
    }
    exit;
}
elsif ( $> != 0 ) {
    exit;
}

my $force = CGI::param('force');

if ( Cpanel::Server::Type::is_dnsonly() ) {
    print_output( 'This feature is disabled for DNSONLY servers.', 'error', 'dns-only-error' );
    print_footer();
    exit;
}

local $SIG{'PIPE'} = \&Cpanel::PipeHandler::pipeBGMgr;

my ( $Availab, $Current, $OwnVend ) = _handle_exception_as_html(
    sub {
        Whostmgr::Cpaddon::Conf::load( force => $force );
    }
);

my $load_duration = Time::HiRes::tv_interval($start_page) if $debug;

if ( $action eq 'upvend' ) {
    print "<h3>Updating vendor config …</h3>\n";
    my $there_were_changes = 0;
  VENDORLOOP:
    for my $vndinf ( CGI::param('vndinf') ) {
        next if !$vndinf;
        my $name = _get_url( $vndinf, '' );
        if ( $name =~ m{cPanel}i ) {

            # Someone is trying to fool you
            print "<p>3rd party vendor may be attempting to masquerade as cPanel, skipping vendor …</p>\n";
            next;
        }

        if ( $name && $name =~ m/^\w+$/ ) {

            my $htmlsafe_name = CGI::escapeHTML($name);

            if ( !exists $OwnVend->{$name} ) {
                my $cphost = _get_url( $vndinf, 'cphost=1' );
                my $cphuri = _get_url( $vndinf, 'cphuri=1' );
                my $palmd5 = _get_url( $vndinf, 'palmd5=1' );

                $cphuri = "/$cphuri" if !Cpanel::StringFunc::Match::beginmatch( $cphuri, '/' );
                $cphuri = Cpanel::StringFunc::Trim::endtrim( $cphuri, '/' );

                if ( $cphost && $cphuri && $palmd5 ) {    # we already know $name is ok
                    print qq(Adding Vendor $htmlsafe_name to your config …<br />\n);
                    $OwnVend->{$name} = {
                        'vndinf' => $vndinf,
                        'cphost' => $cphost,
                        'cphuri' => $cphuri,
                        'palmd5' => $palmd5,
                    };

                    eval {

                        Cpanel::HttpRequest->new( hideOutput => 1 )->request(
                            'host'     => $OwnVend->{$name}->{'cphost'},
                            'url'      => "$OwnVend->{$name}->{'cphuri'}/cPAddonsAvailable/$name.pm",
                            'destfile' => "/usr/local/cpanel/cpaddons/cPAddonsAvailable/$name.pm",
                            Whostmgr::Cpaddon::Signatures::httprequest_sig_flags($name)
                        );

                        Cpanel::HttpRequest->new( hideOutput => 1 )->request(
                            'host'     => $OwnVend->{$name}->{'cphost'},
                            'url'      => "$OwnVend->{$name}->{'cphuri'}/cPAddonsMD5/$name.pm",
                            'destfile' => "/usr/local/cpanel/cpaddons/cPAddonsMD5/$name.pm",
                            Whostmgr::Cpaddon::Signatures::httprequest_sig_flags($name)
                        );
                    };
                    if ($@) {
                        print "Failed to fetch vendor modules for '$htmlsafe_name'<br />\n" . CGI::escapeHTML($@);
                        next VENDORLOOP;
                    }

                    my @check = ( "/usr/local/cpanel/cpaddons/cPAddonsMD5/$name.pm", "/usr/local/cpanel/cpaddons/cPAddonsAvailable/$name.pm" );
                    for my $pm (@check) {
                        if ( !_perl_c($pm) ) {
                            my $safe = CGI::escapeHTML($vndinf);
                            print "Url &quot;$safe&quot; did not work or was otherwise invalid.<br />\n";    # same error used elsewhere, will get updated properly in 2.0
                            unlink @check;
                            last;
                        }
                    }

                    $there_were_changes++;
                }
            }
            else {
                print "The vendor $htmlsafe_name is already in your configuration.<br />\n";
            }
        }
        else {
            my $safe = CGI::escapeHTML($vndinf);
            print "Url &quot;$safe&quot; did not work or was otherwise invalid.<br />\n";
        }
    }

    for ( CGI::param('remove') ) {
        my $escaped = CGI::escapeHTML($_);
        print "Removing $escaped from your list …<br />\n";
        $there_were_changes++;
        delete $OwnVend->{$_};
    }

    _handle_exception_as_html( sub { Whostmgr::Cpaddon::Conf::write_conf() } ) if $there_were_changes;
    print qq(<p>[<a href="$ENV{SCRIPT_NAME}?">Back</a>]</p>\n);
    print_footer();
}
elsif ( $action eq 'rmpm' ) {
    my $mod     = CGI::param('mod');
    my $manager = Whostmgr::Addons::Manager->new(

        # Flags
        debug => $debug,

        # Delegated operations
        notify_fn => \&print_output,
    );
    print '<div id="processing">' . "\n";
    $manager->purge($mod);
    print '</div>' . "\n";

    my $exp_debug = $debug ? "debug=1" : "";
    print qq(<p>[<a href="$ENV{'SCRIPT_NAME'}?$exp_debug">Back</a>]</p>\n);
}
elsif ( $action eq 'update' ) {

    # Factor out handling of html/non-html into one string and one function. The only reason
    # for using an anonymous sub here was to keep the format close to the place it is used.

    print '<div id="processing">' . "\n";
    print_output( "Updating Local Addons Database …", 'line' );

    my $basesyncdir = '/cpanelsync/cpaddons';                     # no trailing slash
    my %CPSRC       = Cpanel::Config::Sources::loadcpsources();

    _cpanelsync(
        Whostmgr::Cpaddon::Signatures::cpanelsync_sig_flags('cPanel'),
        $CPSRC{'HTTPUPDATE'},
        "$basesyncdir/cPAddonsMD5",
        '/usr/local/cpanel/cpaddons/cPAddonsMD5',
    );

    for my $vnd ( keys %$OwnVend ) {
        next if !$vnd;
        eval { Cpanel::HttpRequest->new( 'htmlOutput' => 1 )->request( 'host' => $OwnVend->{$vnd}->{'cphost'}, 'url' => "$OwnVend->{$vnd}->{'cphuri'}/cPAddonsMD5/$vnd.pm", 'destfile' => "/usr/local/cpanel/cpaddons/cPAddonsMD5/$vnd.pm", Whostmgr::Cpaddon::Signatures::httprequest_sig_flags($vnd) ); };

        eval "use cPAddonsMD5\:\:$vnd;";    ##no critic(ProhibitStringyEval)
        unlink "/usr/local/cpanel/cpaddons/cPAddonsMD5/$vnd.pm" if $@;
    }

    my $config_definitions = {};
    print "$br\n";

    my $force = CGI::param('force');
    for my $amod ( sort keys %$Availab ) {

        # Unify the vendors
        require Cpanel::SafeStorable;
        my $vendors = Cpanel::SafeStorable::dclone($OwnVend);
        $vendors->{'cPanel'} = {
            cphost => $CPSRC{HTTPUPDATE},
            cphuri => $basesyncdir,
        };

        my $manager = Whostmgr::Addons::Manager->new(
            CURRENT_MODULES   => $Current,
            AVAILABLE_MODULES => $Availab,
            VENDORS           => $vendors,

            # Flags
            debug      => $debug,
            htmlOutput => 1,

            # Delegated operations
            notify_fn      => \&print_output,
            sync_cpanel_fn => \&_cpanelsync,
            check_perl_fn  => \&_perl_c,
        );

        if ( CGI::param($amod) ) {
            $config_definitions->{$amod} = $manager->install( $amod, $force );
        }
        else {
            $config_definitions->{$amod} = $manager->uninstall( $amod, $force );
        }
    }

    print '</div>' . "\n";

    _handle_exception_as_html(
        sub {
            Whostmgr::Cpaddon::Conf::write_conf( config_definitions => $config_definitions );
        }
    );

    my $exp_debug = $debug ? "debug=1" : "";
    print qq(<p>[<a href="$ENV{'SCRIPT_NAME'}?$exp_debug">Back</a>]</p>\n) unless $nohtml;

    print_footer() unless $nohtml;

    # refresh the touch flag to disable cpaddons when removing the last one
    Cpanel::SafeRun::Simple::saferunnoerror( $^X, "/usr/local/cpanel/install/CheckCpAddons.pm" );

}
elsif ( $action eq 'showsecurity' ) {
    my $mod        = CGI::param('addon') || return;
    my @components = grep { !tr/A-Za-z0-9_//c } split /::/, $mod;
    exit unless scalar(@components) == 3;
    my ( $vend, $cat, $name ) = @components;
    exit unless -e "/usr/local/cpanel/cpaddons/$vend/$cat/$name.pm";
    require "/usr/local/cpanel/cpaddons/$vend/$cat/$name.pm";
    no strict 'refs';
    my $security =
         $vend eq 'cPanel'
      && defined ${"$vend\:\:$cat\:\:$name\:\:meta_info"}
      && exists ${"$vend\:\:$cat\:\:$name\:\:meta_info"}->{'security'} ? ${"$vend\:\:$cat\:\:$name\:\:meta_info"}->{'security'} : 'No information available';

    print qq{
        <h4>${\CGI::escapeHTML($mod)}</h4>
        <div>
            <table width="90%">
                <tr>
                    <td>${\CGI::escapeHTML($security)}</td>
                </tr>
            </table>
        </div>
    };
    print_footer();
    exit;
}
else {
    # Show the list of addons available/installed

    _handle_exception_as_html( sub { Whostmgr::Cpaddon::Conf::write_conf( force => 1, if_missing => 1 ) } );

    my $deprecation_warning = div_warning( <<EOS );
    We have <b>deprecated</b> this interface in cPanel & WHM version 104 and plan to remove it in future versions.
    For more information, read our <a href="https://docs.cpanel.net/knowledge-base/cpanel-product/cpanel-deprecation-plan/" target="_blank">cPanel Deprecation Plan</a> documentation.
EOS

    print qq[<div class="col-xs-12 col-sm-12 col-md-8 col-lg-6">
    $deprecation_warning
    </div>];

    my $needs_notices = 0;
    for my $app ( sort keys %$Availab ) {
        my ( $vend, $cat, $name ) = split /\:\:/, $app;
        my $has_pm        = -e "/usr/local/cpanel/cpaddons/$vend/$cat/$name.pm";
        my $is_deprecated = Cpanel::cPAddons::Filter::is_deprecated($app);
        my $is_installed  = $Current->{$app}->{'VERSION'} ? 1 : 0;
        if ( $is_deprecated && ( $is_installed || $has_pm ) ) {
            $needs_notices = 1;
            last;    # We only care if at least one is needed.
        }
    }

    my $notice_header = $needs_notices ? "<th>Notices</th>\n" : "";
    print qq{
    <div class="row">
        <div class="col-xs-12 col-sm-12 col-md-9 col-lg-8">
            <form action="$ENV{'SCRIPT_NAME'}" method="post">
                <input type="hidden" name="action" value="update" />

                <table id="addon-list"
                       class="table table-striped table-condensed"
                       summary="Available cPAddons Site Software Installations">
                    <tr>
                        <th>Installed</th>
                        <th>Vendor</th>
                        <th>Category</th>
                        <th>Name</th>
                        <th>Version</th>
                        $notice_header
                    </tr>
        };
    my $do_pm_warn = 0;

    for my $app ( sort keys %$Availab ) {
        my ( $vend, $cat, $name ) = split /\:\:/, $app;
        my $has_pm  = -e "/usr/local/cpanel/cpaddons/$vend/$cat/$name.pm";
        my $has_lib = -d "/usr/local/cpanel/cpaddons/$vend/$cat/$name/";

        # Do not list the addon if it is blacklisted
        next if Cpanel::cPAddons::Filter::is_blacklisted($app);

        my $is_deprecated = Cpanel::cPAddons::Filter::is_deprecated($app);
        my $is_installed  = $Current->{$app}->{'VERSION'} ? 1 : 0;

        my $checked  = $Current->{$app}->{'VERSION'}                    ? ' checked="checked"'   : '';
        my $disabled = $is_deprecated && !$Current->{$app}->{'VERSION'} ? ' disabled="disabled"' : '';

        # Do not list the addon if its not installed and has been deprecatated
        if ( !$Current->{$app}->{'VERSION'} && $is_deprecated ) {
            my $is_rpm = !!$Availab->{$app}{package}{rpm_name};
            next if $is_rpm;
            next if !$has_lib && !$has_pm;    # Legacy addons supported a limbo state where you can't install, but existing installs are still usable.
        }

        my $unpmfile = !$has_lib && $has_pm
          ? qq(
                    <a href="$ENV{'SCRIPT_NAME'}?action=rmpm&mod=$app">
                        Completely Remove
                    </a> **
                )
          : '';

        my $pm_bad;
        if ( -e "/usr/local/cpanel/cpaddons/$vend/$cat/$name.pm" ) {
            $pm_bad = not eval {
                require "/usr/local/cpanel/cpaddons/$vend/$cat/$name.pm";
                1;
            };
        }

        $do_pm_warn++ if $unpmfile;
        $cat =~ s/\_/ /g;
        $vend = ( $vend eq 'cPanel' ) ? "cPanel, L.L.C." : $vend;

        my $display_app_name = Cpanel::cPAddons::LegacyNaming::get_app_name($app);

        my $deprecated_warning = '';
        if ($is_deprecated) {
            my $warning = ' ' . ( $has_lib ? "If the application is uninstalled it can not be reinstalled." : "If the application is completely removed, it can not be reinstalled." );
            my $id      = $app . "-legacy-warning";
            $deprecated_warning = div_warning( "This application is deprecated.$warning", $id );
        }

        my $notice_column = $needs_notices ? "<td>$deprecated_warning</td>\n" : "";
        print qq(
            <tr>
                <td class="center">
                    <span class="checkbox">
                        <input type="checkbox" name="$app" value="1"$checked$disabled />
                    </span>
                </td>
                <td>$vend</td>
                <td>$cat</td>
                <td>$display_app_name</td>
                <td><span class="text-nowrap">$Availab->{$app}->{'version'}$unpmfile</span></td>
                $notice_column
            </tr>
        );

        if ($pm_bad) {
            print qq(
                <tr>
                    <td></td>
                    <td colspan="4" class="error">
                        Error loading $display_app_name: $@
                    </td>
                </tr>
            );
        }
    }

    print qq{
                <tr>
                    <td class="center">
                        <span class="checkbox">
                            <input type="checkbox" name="force" value="1" />
                        </span>
                    </td>
                    <td align="left" colspan="4">
                        Force Refresh of All cPAddons Site Software Sources
                    </td>
                </tr>
            </table>
            <input type="submit" value="Update cPAddon Config" class="btn btn-primary" id="btn-update-cpaddon-config" />
            <input type="hidden" name="debug" id="debug" value="$debug">
        </form>
    </div>
</div>
    };

    my $package_warning_msg = qq[<b>**</b> You should only completely remove the package if you have <a target="_blank" href="cpaddons_report.pl">uninstalled all cPAddons Site Software</a> first. Otherwise, you cannot remove the ophaned installations until you reinstall the module.];
    my $package_warning_div = div_warning( $package_warning_msg, 'completely-remove-warning' );

    print qq{
<br/>
<div class="row">
    <div class="col-xs-12 col-sm-12 col-md-8 col-lg-6">
        $package_warning_div
    </div>
</div>
    } if $do_pm_warn;

    my $div_warning_3rd_party = div_warning("This feature allows installation of 3rd party cPAddons Site Software packages that cPanel, L.L.C. does not provide.");

    # Build the add vendors form
    print qq(
    <div class="row">
        <div class="col-xs-12 col-sm-12 col-md-8 col-lg-6">
            <h3>Add or Remove Vendors</h3>
            $div_warning_3rd_party
    );
    my $vndinf     = CGI::escapeHTML( CGI::param('vndinf') );
    my $vendorlist = '';
    for my $vnd ( sort keys %$OwnVend ) {
        next if !$vnd;
        next if ref $OwnVend->{$vnd} ne 'HASH';
        next if !keys %{ $OwnVend->{$vnd} };
        $vendorlist .= qq(
        <tr>
            <td>$vnd</td>
            <td class="right">
                <span class="checkbox">
                    <input type="checkbox" name="remove" value="$vnd" />
                </span>
            </td>
        </tr>
        );
    }

    $vendorlist = qq(
        <tr>
            <th>Vendor</th>
            <th>Remove</th>
        </tr>
        $vendorlist
    ) if $vendorlist;

    my $url_count  = int CGI::param('url_count') && int CGI::param('url_count') < 15 ? int CGI::param('url_count') : 1;
    my $url_fields = qq(
        <tr>
            <td>URL:</td>
            <td>
                <input type="text" name="vndinf" size="40" value="$vndinf" class="form-control" />
            </td>
        </tr>
    ) x $url_count;

    print <<"ADD_END";
        <form action="$ENV{SCRIPT_NAME}" method="post">
            <input type="hidden" name="action" value="upvend" />
            <table class="table table-striped table-condensed">
                $vendorlist
                <tr>
                    <td colspan="2">Vendor's information URL:</td>
                </tr>
                $url_fields
                <tr>
                    <td>&nbsp;</td>
                    <td>
                        <input type="submit" value="Update Vendors" class="btn btn-primary" />
                    </td>
                </tr>
            </table>
            <input type="hidden" name="debug" id="debug" value="$debug">
        </form>

        <form action="$ENV{SCRIPT_NAME}" method="post" class="form-inline">
            <table>
                <tr>
                    <td colspan="2">Add additional vendor URL fields:</td>
                </tr>
                <tr>
                    <td colspan="2">
                        <!-- TODO: Remove this silly text field expansion -->
                        <select name="url_count" class="form-control">
                            <option selected value="1">1</option>
                            <option value="2">2</option>
                            <option value="3">3</option>
                            <option value="4">4</option>
                            <option value="5">5</option>
                            <option value="6">6</option>
                            <option value="7">7</option>
                            <option value="8">8</option>
                            <option value="9">9</option>
                            <option value="10">10</option>
                            <option value="11">11</option>
                            <option value="12">12</option>
                            <option value="13">13</option>
                            <option value="14">14</option>
                        </select>
                        <input type="submit" value="Add additional URL fields" class="btn btn-primary" />
                    </td>
                </tr>
            </table>
            <input type="hidden" name="debug" id="debug" value="$debug">
        </form>
    </div>
</div>
<br/>
ADD_END
    print_footer();
}

print_performance() if $debug;

# TODO: Need to print a std-footer as the page is never really finished

sub print_performance {
    my $page_duration   = Time::HiRes::tv_interval($start_page);
    my $render_duration = $page_duration - $load_duration;
    print qq{
        whole page:  $page_duration<br/>
        render only: $render_duration<br/>
    };
    return;
}

sub _get_url {
    my ( $url, $get ) = @_;

    # Cpanel::HttpRequest does not allow for assigning to anything but a file, so we:
    require LWP::UserAgent;

    my $ua = LWP::UserAgent->new;
    $ua->timeout(10);

    my $res = $ua->get( $get ? "$url?$get" : $url );
    return $res->is_success() ? $res->content() : '';    # return content or empty string
}

# TODO: Move to a module, where?
sub _perl_c {
    my ($file) = @_;
    return if !defined $file || $file eq '';

    # string context so that the '>/dev/null 2>&1' will work
    return system( '/usr/local/cpanel/3rdparty/bin/perl -c ' . quotemeta($file) . ' >/dev/null 2>&1' ) == 0 ? 1 : 0;
}

sub _cpanelsync {
    my @arguments = @_;

    my $out_fh;
    my $buf = '';
    my $pid = IPC::Open3::open3( undef, $out_fh, $out_fh, '/usr/local/cpanel/scripts/cpanelsync', @arguments );

    while ( sysread( $out_fh, $buf, 1024 ) ) {
        $buf = Cpanel::Encoder::Tiny::safe_html_encode_str($buf);
        $buf =~ s{\n}{<br />\n}g unless $nohtml;
        print $buf;
    }

    waitpid( $pid, 0 );

    return $? ? 0 : 1;
}

sub print_header {
    Cpanel::Template::process_template(
        'whostmgr',
        {
            'print'                      => 1,
            'template_file'              => 'master_templates/_defheader.tmpl',
            'theme'                      => 'bootstrap',
            'app_key'                    => 'install_cpaddons_site_software',
            'include_legacy_stylesheets' => 1,
            'extrastyle'                 => qq(
                .table td.center input { margin-left: auto; margin-right: auto }
                .table td.right input { float: right }
                .text-nowrap { white-space: nowrap; }
                .whm-app-title__image{width:48px;height:48px}
                #addon-list {min-width: 600px; }
                #addon-list .alert { margin-bottom: 0; max-width: 400px; }
                #processing .alert { margin-bottom: 10px; margin-top: 5px; max-width: 1024px; }
                #processing p { margin-bottom: 15px }
            ),
        },
    );
    return;
}

sub print_footer {
    Cpanel::Template::process_template(
        'whostmgr',
        {
            'print'                      => 1,
            'template_file'              => 'master_templates/_deffooter.tmpl',
            'theme'                      => 'bootstrap',
            'include_legacy_stylesheets' => 1,
            'skipsupport'                => 1,
        },
    );
    return;
}

=pod

=head2 div_warning( $msg, $id = '' )

Returns an html '<div>' warning to display the message C<$msg>.
Optionally can set the div id by providing C<$id>.

=cut

sub div_warning {
    my ( $msg, $id ) = @_;

    return '' unless length $msg;
    $id //= '';

    return <<"EOS";
    <div class="alert alert-warning">
        <span class="glyphicon glyphicon-exclamation-sign"></span>
        <div class="alert-message" id="$id">
        <strong>Warning:</strong>
        $msg
        </div>
    </div>
EOS

}

sub _handle_exception_as_html {
    my ($func) = @_;

    my $context = wantarray();
    if ( !$context && defined($context) ) {
        Carp::croak('Defect: _handle_exception_as_html called in scalar context. Please use list or void.');    # scalar will cause the function to mishandle the return due to the use of an array
    }

    my @result = eval { $func->() };
    if ( my $exception = $@ ) {
        my ( $success, $output ) = Cpanel::Template::process_template(
            'whostmgr',
            {
                template_file => '/usr/local/cpanel/whostmgr/docroot/templates/cpaddons/exception.tmpl',
                data          => { exception => $exception },
            }
        );
        print $$output;
        exit;
    }
    return @result;
}

sub print_output {
    my ( $message, $type, $id, $classes ) = @_;

    # Expand any internal linefeeds
    $message =~ s/\n/$br/g;
    return $output_handler->message( $type, $message, $id, undef, $classes );
}
Back to Directory File Manager