<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># --
# Kernel/Modules/AdminPackageManager.pm - manage software packages
# Copyright (C) 2001-2014 OTRS AG, http://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --

package Kernel::Modules::AdminPackageManager;
## nofilter(TidyAll::Plugin::OTRS::Perl::DBObject)

use strict;
use warnings;

use XML::FeedPP;

use Kernel::System::Package;
use Kernel::System::Web::UploadCache;
use Kernel::System::Cache;

sub new {
    my ( $Type, %Param ) = @_;

    # allocate new hash for object
    my $Self = {%Param};
    bless( $Self, $Type );

    # check needed objects
    for my $Needed (qw(ParamObject DBObject LayoutObject LogObject ConfigObject MainObject)) {
        if ( !$Self-&gt;{$Needed} ) {
            $Self-&gt;{LayoutObject}-&gt;FatalError( Message =&gt; "Got no $Needed!" );
        }
    }

    $Self-&gt;{PackageObject}     = Kernel::System::Package-&gt;new(%Param);
    $Self-&gt;{UploadCacheObject} = Kernel::System::Web::UploadCache-&gt;new(%Param);
    $Self-&gt;{CacheObject}       = Kernel::System::Cache-&gt;new(%Param);

    return $Self;
}

sub Run {
    my ( $Self, %Param ) = @_;

    my $Source = $Self-&gt;{UserRepository} || '';
    my %Errors;

    # ------------------------------------------------------------ #
    # check mod perl version and Apache::Reload
    # ------------------------------------------------------------ #

    if ( exists $ENV{MOD_PERL} ) {
        if ( defined $mod_perl::VERSION ) {    ## no critic
            if ( $mod_perl::VERSION &gt;= 1.99 ) {    ## no critic

                # check if Apache::Reload is loaded
                my $ApacheReload = 0;
                for my $Module ( sort keys %INC ) {
                    $Module =~ s/\//::/g;
                    $Module =~ s/\.pm$//g;
                    if ( $Module eq 'Apache::Reload' || $Module eq 'Apache2::Reload' ) {
                        $ApacheReload = 1;
                    }
                }
                if ( !$ApacheReload ) {
                    return $Self-&gt;{LayoutObject}-&gt;ErrorScreen(
                        Message =&gt;
                            'Sorry, Apache::Reload is needed as PerlModule and '
                            .
                            'PerlInitHandler in Apache config file. See also scripts/apache2-httpd.include.conf. '
                            .
                            'Alternatively, you can use the cmd tool bin/otrs.PackageManager.pl to install packages!'
                    );
                }
            }
        }
    }

    # secure mode message (don't allow this action until secure mode is enabled)
    if ( !$Self-&gt;{ConfigObject}-&gt;Get('SecureMode') ) {
        return $Self-&gt;{LayoutObject}-&gt;SecureMode();
    }

    # ------------------------------------------------------------ #
    # view diff file
    # ------------------------------------------------------------ #
    if ( $Self-&gt;{Subaction} eq 'ViewDiff' ) {
        my $Name    = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Name' )    || '';
        my $Version = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Version' ) || '';
        my $Location = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Location' );

        # get package
        my $Package = $Self-&gt;{PackageObject}-&gt;RepositoryGet(
            Name    =&gt; $Name,
            Version =&gt; $Version,
            Result  =&gt; 'SCALAR',
        );
        if ( !$Package ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
        }
        my %Structure = $Self-&gt;{PackageObject}-&gt;PackageParse( String =&gt; $Package );
        my $File = '';
        if ( ref $Structure{Filelist} eq 'ARRAY' ) {
            for my $Hash ( @{ $Structure{Filelist} } ) {
                if ( $Hash-&gt;{Location} eq $Location ) {
                    $File = $Hash-&gt;{Content};
                }
            }
        }
        my $LocalFile = $Self-&gt;{ConfigObject}-&gt;Get('Home') . "/$Location";

        # do not allow to read file with including .. path (security related)
        $LocalFile =~ s/\.\.//g;
        if ( !$File ) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'FileDiff',
                Data =&gt; {
                    Location =&gt; $Location,
                    Name     =&gt; $Name,
                    Version  =&gt; $Version,
                    Diff     =&gt; "No such file $LocalFile in package!",
                },
            );
        }
        elsif ( !-e $LocalFile ) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'FileDiff',
                Data =&gt; {
                    Location =&gt; $Location,
                    Name     =&gt; $Name,
                    Version  =&gt; $Version,
                    Diff     =&gt; "No such file $LocalFile in local file system!",
                },
            );
        }
        elsif ( -e $LocalFile ) {
            my $Content = $Self-&gt;{MainObject}-&gt;FileRead(
                Location =&gt; $LocalFile,
                Mode     =&gt; 'binmode',
            );
            if ($Content) {
                $Self-&gt;{MainObject}-&gt;Require('Text::Diff');
                my $Diff = Text::Diff::diff( \$File, $Content, { STYLE =&gt; 'OldStyle' } );
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; "FileDiff",
                    Data =&gt; {
                        Location =&gt; $Location,
                        Name     =&gt; $Name,
                        Version  =&gt; $Version,
                        Diff     =&gt; $Diff,
                    },
                );
            }
            else {
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; "FileDiff",
                    Data =&gt; {
                        Location =&gt; $Location,
                        Name     =&gt; $Name,
                        Version  =&gt; $Version,
                        Diff     =&gt; "Can't read $LocalFile!",
                    },
                );
            }
        }
        my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
        $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
        $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
            TemplateFile =&gt; 'AdminPackageManager',
        );
        $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
        return $Output;
    }

    # ------------------------------------------------------------ #
    # view package
    # ------------------------------------------------------------ #
    if ( $Self-&gt;{Subaction} eq 'View' ) {
        my $Name    = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Name' )    || '';
        my $Version = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Version' ) || '';
        my $Location = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Location' );
        my %Frontend;

        # get package
        my $Package = $Self-&gt;{PackageObject}-&gt;RepositoryGet(
            Name    =&gt; $Name,
            Version =&gt; $Version,
            Result  =&gt; 'SCALAR',
        );
        if ( !$Package ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
        }

        # parse package
        my %Structure = $Self-&gt;{PackageObject}-&gt;PackageParse( String =&gt; $Package );

        # online verification
        my $Verified = $Self-&gt;{PackageObject}-&gt;PackageVerify(
            Package   =&gt; $Package,
            Structure =&gt; \%Structure,
        ) || 'verified';
        my %VerifyInfo = $Self-&gt;{PackageObject}-&gt;PackageVerifyInfo();

        # translate description
        if ( $Self-&gt;{LayoutObject}-&gt;{LanguageObject} ) {
            $VerifyInfo{Description} = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get(
                $VerifyInfo{Description}
            );
        }

        # deploy check
        my $Deployed = $Self-&gt;{PackageObject}-&gt;DeployCheck(
            Name    =&gt; $Name,
            Version =&gt; $Version,
        );
        my %DeployInfo = $Self-&gt;{PackageObject}-&gt;DeployCheckInfo();
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Package',
            Data =&gt; { %Param, %Frontend, Name =&gt; $Name, Version =&gt; $Version, },
        );
        for my $PackageAction (qw(DownloadLocal Rebuild Reinstall)) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'Package' . $PackageAction,
                Data =&gt; {
                    %Param,
                    %Frontend,
                    Name    =&gt; $Name,
                    Version =&gt; $Version,
                },
            );
        }

        # check if file is requested
        if ($Location) {
            if ( ref $Structure{Filelist} eq 'ARRAY' ) {
                for my $Hash ( @{ $Structure{Filelist} } ) {
                    if ( $Hash-&gt;{Location} eq $Location ) {
                        return $Self-&gt;{LayoutObject}-&gt;Attachment(
                            Filename    =&gt; $Location,
                            ContentType =&gt; 'application/octet-stream',
                            Content     =&gt; $Hash-&gt;{Content},
                        );
                    }
                }
            }
        }
        my @DatabaseBuffer;

        # correct any 'dos-style' line endings - http://bugs.otrs.org/show_bug.cgi?id=9838
        ${$Package} =~ s{\r\n}{\n}xmsg;

        # create MD5 sum and add it into existing package structure
        my $MD5sum = $Self-&gt;{MainObject}-&gt;MD5sum( String =&gt; $Package );

        $Structure{MD5sum} = {
            Tag     =&gt; 'MD5sum',
            Content =&gt; $MD5sum,
        };

        for my $Key ( sort keys %Structure ) {

            if ( ref $Structure{$Key} eq 'HASH' ) {

                if ( $Key =~ /^(Description|Filelist)$/ ) {
                    $Self-&gt;{LayoutObject}-&gt;Block(
                        Name =&gt; "PackageItem$Key",
                        Data =&gt; { Tag =&gt; $Key, %{ $Structure{$Key} } },
                    );
                }
                elsif ( $Key =~ /^Database(Install|Reinstall|Upgrade|Uninstall)$/ ) {

                    for my $Type (qw(pre post)) {
                        for my $Hash ( @{ $Structure{$Key}-&gt;{$Type} } ) {
                            if ( $Hash-&gt;{TagType} eq 'Start' ) {
                                if ( $Hash-&gt;{Tag} =~ /^Table/ ) {
                                    $Self-&gt;{LayoutObject}-&gt;Block(
                                        Name =&gt; "PackageItemDatabase",
                                        Data =&gt; { %{$Hash}, TagName =&gt; $Key, Type =&gt; $Type },
                                    );
                                    push @DatabaseBuffer, $Hash;
                                }
                                else {
                                    $Self-&gt;{LayoutObject}-&gt;Block(
                                        Name =&gt; "PackageItemDatabaseSub",
                                        Data =&gt; { %{$Hash}, TagName =&gt; $Key, },
                                    );
                                    push @DatabaseBuffer, $Hash;
                                }
                            }
                            if ( $Hash-&gt;{Tag} =~ /^Table/ &amp;&amp; $Hash-&gt;{TagType} eq 'End' ) {
                                push @DatabaseBuffer, $Hash;
                                my @SQL = $Self-&gt;{DBObject}-&gt;SQLProcessor(
                                    Database =&gt; \@DatabaseBuffer
                                );
                                my @SQLPost = $Self-&gt;{DBObject}-&gt;SQLProcessorPost();
                                push @SQL, @SQLPost;
                                for my $SQL (@SQL) {
                                    $Self-&gt;{LayoutObject}-&gt;Block(
                                        Name =&gt; "PackageItemDatabaseSQL",
                                        Data =&gt; { TagName =&gt; $Key, SQL =&gt; $SQL, },
                                    );
                                }
                                @DatabaseBuffer = ();
                            }
                        }
                    }
                }
                else {
                    $Self-&gt;{LayoutObject}-&gt;Block(
                        Name =&gt; 'PackageItemGeneric',
                        Data =&gt; { Tag =&gt; $Key, %{ $Structure{$Key} } },
                    );
                }
            }
            elsif ( ref $Structure{$Key} eq 'ARRAY' ) {

                for my $Hash ( @{ $Structure{$Key} } ) {
                    if ( $Key =~ /^(Description|ChangeLog)$/ ) {
                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; "PackageItem$Key",
                            Data =&gt; { %{$Hash}, Tag =&gt; $Key, },
                        );
                    }
                    elsif ( $Key =~ /^Code/ ) {
                        $Hash-&gt;{Content} = $Self-&gt;{LayoutObject}-&gt;Ascii2Html(
                            Text           =&gt; $Hash-&gt;{Content},
                            HTMLResultMode =&gt; 1,
                            NewLine        =&gt; 72,
                        );
                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; "PackageItemCode",
                            Data =&gt; { Tag =&gt; $Key, %{$Hash} },
                        );
                    }
                    elsif ( $Key =~ /^(Intro)/ ) {
                        if ( $Hash-&gt;{Format} &amp;&amp; $Hash-&gt;{Format} =~ /plain/i ) {
                            $Hash-&gt;{Content}
                                = '&lt;pre class="contentbody"&gt;' . $Hash-&gt;{Content} . '&lt;/pre&gt;';
                        }
                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; "PackageItemIntro",
                            Data =&gt; { %{$Hash}, Tag =&gt; $Key, },
                        );
                    }
                    elsif ( $Hash-&gt;{Tag} =~ /^(File)$/ ) {

                        # add human readable file size
                        if ( $Hash-&gt;{Size} ) {

                            # remove meta data in files
                            if ( $Hash-&gt;{Size} &gt; ( 1024 * 1024 ) ) {
                                $Hash-&gt;{Size} = sprintf "%.1f MBytes",
                                    ( $Hash-&gt;{Size} / ( 1024 * 1024 ) );
                            }
                            elsif ( $Hash-&gt;{Size} &gt; 1024 ) {
                                $Hash-&gt;{Size} = sprintf "%.1f KBytes", ( ( $Hash-&gt;{Size} / 1024 ) );
                            }
                            else {
                                $Hash-&gt;{Size} = $Hash-&gt;{Size} . ' Bytes';
                            }
                        }
                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; "PackageItemFilelistFile",
                            Data =&gt; {
                                Name    =&gt; $Name,
                                Version =&gt; $Version,
                                %{$Hash},
                            },
                        );
                        if ( $DeployInfo{File}-&gt;{ $Hash-&gt;{Location} } ) {
                            if ( $DeployInfo{File}-&gt;{ $Hash-&gt;{Location} } =~ /different/ ) {
                                $Self-&gt;{LayoutObject}-&gt;Block(
                                    Name =&gt; "PackageItemFilelistFileNoteDiff",
                                    Data =&gt; {
                                        Name    =&gt; $Name,
                                        Version =&gt; $Version,
                                        %{$Hash},
                                        Message =&gt; $DeployInfo{File}-&gt;{ $Hash-&gt;{Location} },
                                        Icon    =&gt; 'IconNotReady',
                                    },
                                );
                            }
                            else {
                                $Self-&gt;{LayoutObject}-&gt;Block(
                                    Name =&gt; "PackageItemFilelistFileNote",
                                    Data =&gt; {
                                        Name    =&gt; $Name,
                                        Version =&gt; $Version,
                                        %{$Hash},
                                        Message =&gt; $DeployInfo{File}-&gt;{ $Hash-&gt;{Location} },
                                        Icon    =&gt; 'IconNotReadyGrey',
                                    },
                                );
                            }
                        }
                        else {
                            $Self-&gt;{LayoutObject}-&gt;Block(
                                Name =&gt; "PackageItemFilelistFileNote",
                                Data =&gt; {
                                    Name    =&gt; $Name,
                                    Version =&gt; $Version,
                                    %{$Hash},
                                    Message =&gt; 'ok',
                                    Icon    =&gt; 'IconReady',
                                },
                            );
                        }
                    }
                    else {
                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; "PackageItemGeneric",
                            Data =&gt; { %{$Hash}, Tag =&gt; $Key, },
                        );
                    }
                }
            }
        }
        my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
        $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
        if ( !$Deployed ) {
            $Output .= $Self-&gt;{LayoutObject}-&gt;Notify(
                Priority =&gt; 'Error',
                Data     =&gt; "$Name $Version"
                    . ' - $Text{"Package not correctly deployed! Please reinstall the package."}',
                Link =&gt; '$Env{"Baselink"}Action=$Env{"Action"};Subaction=View;Name='
                    . $Name
                    . ';Version='
                    . $Version,
            );
        }

        if ( $Verified ne 'verified' ) {

            $Output .= $Self-&gt;{LayoutObject}-&gt;Notify(
                Priority =&gt; 'Error',
                Data     =&gt; "$Name $Version - "
                    . '$Text{"Package not verified by the OTRS Group! It is recommended not to use this package."}',
            );
        }

        $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
            TemplateFile =&gt; 'AdminPackageManager',
        );
        $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
        return $Output;
    }

    # ------------------------------------------------------------ #
    # view remote package
    # ------------------------------------------------------------ #
    if ( $Self-&gt;{Subaction} eq 'ViewRemote' ) {
        my $File = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'File' ) || '';
        my $Location = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Location' );
        my %Frontend;

        # download package
        my $Package = $Self-&gt;{PackageObject}-&gt;PackageOnlineGet(
            Source =&gt; $Source,
            File   =&gt; $File,
        );
        if ( !$Package ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
        }
        my %Structure = $Self-&gt;{PackageObject}-&gt;PackageParse( String =&gt; $Package );
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Package',
            Data =&gt; { %Param, %Frontend, },
        );
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'PackageDownloadRemote',
            Data =&gt; { %Param, %Frontend, File =&gt; $File, },
        );

        # check if file is requested
        if ($Location) {
            if ( ref $Structure{Filelist} eq 'ARRAY' ) {
                for my $Hash ( @{ $Structure{Filelist} } ) {
                    if ( $Hash-&gt;{Location} eq $Location ) {
                        return $Self-&gt;{LayoutObject}-&gt;Attachment(
                            Filename    =&gt; $Location,
                            ContentType =&gt; 'application/octet-stream',
                            Content     =&gt; $Hash-&gt;{Content},
                        );
                    }
                }
            }
        }
        my @DatabaseBuffer;
        for my $Key ( sort keys %Structure ) {
            if ( ref $Structure{$Key} eq 'HASH' ) {
                if ( $Key =~ /^(Description|Filelist)$/ ) {
                    $Self-&gt;{LayoutObject}-&gt;Block(
                        Name =&gt; "PackageItem$Key",
                        Data =&gt; { Tag =&gt; $Key, %{ $Structure{$Key} } },
                    );
                }
                elsif ( $Key =~ /^Database(Install|Reinstall|Upgrade|Uninstall)$/ ) {
                    for my $Type (qw(pre post)) {
                        for my $Hash ( @{ $Structure{$Key}-&gt;{$Type} } ) {
                            if ( $Hash-&gt;{TagType} eq 'Start' ) {
                                if ( $Hash-&gt;{Tag} =~ /^Table/ ) {
                                    $Self-&gt;{LayoutObject}-&gt;Block(
                                        Name =&gt; "PackageItemDatabase",
                                        Data =&gt; { %{$Hash}, TagName =&gt; $Key, Type =&gt; $Type },
                                    );
                                    push @DatabaseBuffer, $Hash;
                                }
                                else {
                                    $Self-&gt;{LayoutObject}-&gt;Block(
                                        Name =&gt; "PackageItemDatabaseSub",
                                        Data =&gt; { %{$Hash}, TagName =&gt; $Key, },
                                    );
                                    push @DatabaseBuffer, $Hash;
                                }
                            }
                            if ( $Hash-&gt;{Tag} =~ /^Table/ &amp;&amp; $Hash-&gt;{TagType} eq 'End' ) {
                                push @DatabaseBuffer, $Hash;
                                my @SQL = $Self-&gt;{DBObject}-&gt;SQLProcessor(
                                    Database =&gt; \@DatabaseBuffer
                                );
                                my @SQLPost = $Self-&gt;{DBObject}-&gt;SQLProcessorPost();
                                push @SQL, @SQLPost;
                                for my $SQL (@SQL) {
                                    $Self-&gt;{LayoutObject}-&gt;Block(
                                        Name =&gt; "PackageItemDatabaseSQL",
                                        Data =&gt; { TagName =&gt; $Key, SQL =&gt; $SQL, },
                                    );
                                }
                                @DatabaseBuffer = ();
                            }
                        }
                    }
                }
                else {
                    $Self-&gt;{LayoutObject}-&gt;Block(
                        Name =&gt; 'PackageItemGeneric',
                        Data =&gt; { Tag =&gt; $Key, %{ $Structure{$Key} } },
                    );
                }
            }
            elsif ( ref $Structure{$Key} eq 'ARRAY' ) {
                for my $Hash ( @{ $Structure{$Key} } ) {
                    if ( $Key =~ /^(Description|ChangeLog)$/ ) {
                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; "PackageItem$Key",
                            Data =&gt; { %{$Hash}, Tag =&gt; $Key, },
                        );
                    }
                    elsif ( $Key =~ /^Code/ ) {
                        $Hash-&gt;{Content} = $Self-&gt;{LayoutObject}-&gt;Ascii2Html(
                            Text           =&gt; $Hash-&gt;{Content},
                            HTMLResultMode =&gt; 1,
                            NewLine        =&gt; 72,
                        );
                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; "PackageItemCode",
                            Data =&gt; { Tag =&gt; $Key, %{$Hash} },
                        );
                    }
                    elsif ( $Key =~ /^(Intro)/ ) {
                        if ( $Hash-&gt;{Format} &amp;&amp; $Hash-&gt;{Format} =~ /plain/i ) {
                            $Hash-&gt;{Content}
                                = '&lt;pre class="contentbody"&gt;' . $Hash-&gt;{Content} . '&lt;/pre&gt;';
                        }
                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; "PackageItemIntro",
                            Data =&gt; { %{$Hash}, Tag =&gt; $Key, },
                        );
                    }
                    elsif ( $Hash-&gt;{Tag} =~ /^(File)$/ ) {

                        # add human readable file size
                        if ( $Hash-&gt;{Size} ) {

                            # remove meta data in files
                            if ( $Hash-&gt;{Size} &gt; ( 1024 * 1024 ) ) {
                                $Hash-&gt;{Size} = sprintf "%.1f MBytes",
                                    ( $Hash-&gt;{Size} / ( 1024 * 1024 ) );
                            }
                            elsif ( $Hash-&gt;{Size} &gt; 1024 ) {
                                $Hash-&gt;{Size} = sprintf "%.1f KBytes", ( ( $Hash-&gt;{Size} / 1024 ) );
                            }
                            else {
                                $Hash-&gt;{Size} = $Hash-&gt;{Size} . ' Bytes';
                            }
                        }
                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; 'PackageItemFilelistFile',
                            Data =&gt; {
                                Name    =&gt; $Structure{Name}-&gt;{Content},
                                Version =&gt; $Structure{Version}-&gt;{Content},
                                File    =&gt; $File,
                                %{$Hash},
                            },
                        );
                    }
                    else {
                        $Self-&gt;{LayoutObject}-&gt;Block(
                            Name =&gt; 'PackageItemGeneric',
                            Data =&gt; { %{$Hash}, Tag =&gt; $Key, },
                        );
                    }
                }
            }
        }
        my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
        $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
        $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
            TemplateFile =&gt; 'AdminPackageManager',
        );
        $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
        return $Output;
    }

    # ------------------------------------------------------------ #
    # download package
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'Download' ) {
        my $Name    = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Name' )    || '';
        my $Version = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Version' ) || '';

        # get package
        my $Package = $Self-&gt;{PackageObject}-&gt;RepositoryGet(
            Name    =&gt; $Name,
            Version =&gt; $Version,
        );
        if ( !$Package ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
        }
        return $Self-&gt;{LayoutObject}-&gt;Attachment(
            Content     =&gt; $Package,
            ContentType =&gt; 'application/octet-stream',
            Filename    =&gt; "$Name-$Version.opm",
            Type        =&gt; 'attachment',
        );
    }

    # ------------------------------------------------------------ #
    # download remote package
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'DownloadRemote' ) {
        my $File = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'File' ) || '';

        # download package
        my $Package = $Self-&gt;{PackageObject}-&gt;PackageOnlineGet(
            Source =&gt; $Source,
            File   =&gt; $File,
        );

        # check
        if ( !$Package ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
        }
        return $Self-&gt;{LayoutObject}-&gt;Attachment(
            Content     =&gt; $Package,
            ContentType =&gt; 'application/octet-stream',
            Filename    =&gt; $File,
            Type        =&gt; 'attachment',
        );
    }

    # ------------------------------------------------------------ #
    # change repository
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'ChangeRepository' ) {

        # challenge token check for write action
        $Self-&gt;{LayoutObject}-&gt;ChallengeTokenCheck();

        my $Source = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Source' ) || '';
        $Self-&gt;{SessionObject}-&gt;UpdateSessionID(
            SessionID =&gt; $Self-&gt;{SessionID},
            Key       =&gt; 'UserRepository',
            Value     =&gt; $Source,
        );
        return $Self-&gt;{LayoutObject}-&gt;Redirect( OP =&gt; "Action=$Self-&gt;{Action}" );
    }

    # ------------------------------------------------------------ #
    # install package
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'Install' ) {

        # challenge token check for write action
        $Self-&gt;{LayoutObject}-&gt;ChallengeTokenCheck();

        my $Name    = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Name' )    || '';
        my $Version = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Version' ) || '';

        # get package
        my $Package = $Self-&gt;{PackageObject}-&gt;RepositoryGet(
            Name    =&gt; $Name,
            Version =&gt; $Version,
            Result  =&gt; 'SCALAR',
        );

        return $Self-&gt;_InstallHandling( Package =&gt; $Package );
    }

    # ------------------------------------------------------------ #
    # install remote package
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'InstallRemote' ) {

        # challenge token check for write action
        $Self-&gt;{LayoutObject}-&gt;ChallengeTokenCheck();

        my $File = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'File' ) || '';

        # download package
        my $Package = $Self-&gt;{PackageObject}-&gt;PackageOnlineGet(
            Source =&gt; $Source,
            File   =&gt; $File,
        );

        return $Self-&gt;_InstallHandling(
            Package =&gt; $Package,
            Source  =&gt; $Source,
            File    =&gt; $File,
        );
    }

    # ------------------------------------------------------------ #
    # upgrade remote package
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'UpgradeRemote' ) {

        # challenge token check for write action
        $Self-&gt;{LayoutObject}-&gt;ChallengeTokenCheck();

        my $File = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'File' ) || '';

        # download package
        my $Package = $Self-&gt;{PackageObject}-&gt;PackageOnlineGet(
            File   =&gt; $File,
            Source =&gt; $Source,
        );

        return $Self-&gt;_UpgradeHandling(
            Package =&gt; $Package,
            File    =&gt; $File,
            Source  =&gt; $Source,
        );
    }

    # ------------------------------------------------------------ #
    # reinstall package
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'Reinstall' ) {

        # challenge token check for write action
        $Self-&gt;{LayoutObject}-&gt;ChallengeTokenCheck();

        my $Name    = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Name' )    || '';
        my $Version = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Version' ) || '';
        my $IntroReinstallPre = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'IntroReinstallPre' )
            || '';

        # get package
        my $Package = $Self-&gt;{PackageObject}-&gt;RepositoryGet(
            Name    =&gt; $Name,
            Version =&gt; $Version,
            Result  =&gt; 'SCALAR',
        );
        if ( !$Package ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
        }

        # check if we have to show reinstall intro pre
        my %Structure = $Self-&gt;{PackageObject}-&gt;PackageParse( String =&gt; $Package, );

        # intro screen
        my %Data;
        if ( $Structure{IntroReinstall} ) {
            %Data = $Self-&gt;_MessageGet( Info =&gt; $Structure{IntroReinstall}, Type =&gt; 'pre' );
        }
        if ( %Data &amp;&amp; !$IntroReinstallPre ) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'Intro',
                Data =&gt; {
                    %Param,
                    %Data,
                    Subaction =&gt; $Self-&gt;{Subaction},
                    Type      =&gt; 'IntroReinstallPre',
                    Name      =&gt; $Structure{Name}-&gt;{Content},
                    Version   =&gt; $Structure{Version}-&gt;{Content},
                },
            );
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'IntroCancel',
            );
            my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
            $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
            $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
                TemplateFile =&gt; 'AdminPackageManager',
                Data         =&gt; \%Param,
            );
            $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
            return $Output;
        }

        # reinstall screen
        else {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'Reinstall',
                Data =&gt; {
                    %Param,
                    Name    =&gt; $Structure{Name}-&gt;{Content},
                    Version =&gt; $Structure{Version}-&gt;{Content},
                },
            );
            my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
            $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
            $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
                TemplateFile =&gt; 'AdminPackageManager',
            );
            $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
            return $Output;
        }
    }

    # ------------------------------------------------------------ #
    # reinstall action package
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'ReinstallAction' ) {

        # challenge token check for write action
        $Self-&gt;{LayoutObject}-&gt;ChallengeTokenCheck();

        my $Name    = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Name' )    || '';
        my $Version = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Version' ) || '';
        my $IntroReinstallPost = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'IntroReinstallPost' )
            || '';

        # get package
        my $Package = $Self-&gt;{PackageObject}-&gt;RepositoryGet(
            Name    =&gt; $Name,
            Version =&gt; $Version,
        );
        if ( !$Package ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
        }

        # check if we have to show reinstall intro pre
        my %Structure = $Self-&gt;{PackageObject}-&gt;PackageParse( String =&gt; $Package, );

        # intro screen
        if ( !$Self-&gt;{PackageObject}-&gt;PackageReinstall( String =&gt; $Package ) ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen();
        }
        my %Data;
        if ( $Structure{IntroReinstall} ) {
            %Data = $Self-&gt;_MessageGet( Info =&gt; $Structure{IntroReinstall}, Type =&gt; 'post' );
        }
        if ( %Data &amp;&amp; !$IntroReinstallPost ) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'Intro',
                Data =&gt; {
                    %Param,
                    %Data,
                    Subaction =&gt; '',
                    Type      =&gt; 'IntroReinstallPost',
                    Name      =&gt; $Name,
                    Version   =&gt; $Version,
                },
            );
            my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
            $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
            $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
                TemplateFile =&gt; 'AdminPackageManager',
            );
            $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
            return $Output;
        }

        # redirect
        return $Self-&gt;{LayoutObject}-&gt;Redirect( OP =&gt; "Action=$Self-&gt;{Action}" );
    }

    # ------------------------------------------------------------ #
    # uninstall package
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'Uninstall' ) {

        # challenge token check for write action
        $Self-&gt;{LayoutObject}-&gt;ChallengeTokenCheck();

        my $Name    = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Name' )    || '';
        my $Version = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Version' ) || '';
        my $IntroUninstallPre = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'IntroUninstallPre' )
            || '';

        # get package
        my $Package = $Self-&gt;{PackageObject}-&gt;RepositoryGet(
            Name    =&gt; $Name,
            Version =&gt; $Version,
            Result  =&gt; 'SCALAR',
        );
        if ( !$Package ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
        }

        # check if we have to show uninstall intro pre
        my %Structure = $Self-&gt;{PackageObject}-&gt;PackageParse( String =&gt; $Package, );

        # intro screen
        my %Data;
        if ( $Structure{IntroUninstall} ) {
            %Data = $Self-&gt;_MessageGet( Info =&gt; $Structure{IntroUninstall}, Type =&gt; 'pre' );
        }
        if ( %Data &amp;&amp; !$IntroUninstallPre ) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'Intro',
                Data =&gt; {
                    %Param,
                    %Data,
                    Subaction =&gt; $Self-&gt;{Subaction},
                    Type      =&gt; 'IntroUninstallPre',
                    Name      =&gt; $Structure{Name}-&gt;{Content},
                    Version   =&gt; $Structure{Version}-&gt;{Content},
                },
            );
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'IntroCancel',
            );
            my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
            $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
            $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
                TemplateFile =&gt; 'AdminPackageManager',
            );
            $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
            return $Output;
        }

        # uninstall screen
        else {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'Uninstall',
                Data =&gt; {
                    %Param,
                    Name    =&gt; $Structure{Name}-&gt;{Content},
                    Version =&gt; $Structure{Version}-&gt;{Content},
                },
            );
            my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
            $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
            $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
                TemplateFile =&gt; 'AdminPackageManager',
            );
            $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
            return $Output;
        }
    }

    # ------------------------------------------------------------ #
    # uninstall action package
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'UninstallAction' ) {

        # challenge token check for write action
        $Self-&gt;{LayoutObject}-&gt;ChallengeTokenCheck();

        my $Name    = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Name' )    || '';
        my $Version = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Version' ) || '';
        my $IntroUninstallPost = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'IntroUninstallPost' )
            || '';

        # get package
        my $Package = $Self-&gt;{PackageObject}-&gt;RepositoryGet(
            Name    =&gt; $Name,
            Version =&gt; $Version,
        );
        if ( !$Package ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
        }

        # parse package
        my %Structure = $Self-&gt;{PackageObject}-&gt;PackageParse( String =&gt; $Package, );

        # unsinstall the package
        if ( !$Self-&gt;{PackageObject}-&gt;PackageUninstall( String =&gt; $Package ) ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen();
        }

        # intro screen
        my %Data;
        if ( $Structure{IntroUninstall} ) {
            %Data = $Self-&gt;_MessageGet( Info =&gt; $Structure{IntroUninstall}, Type =&gt; 'post' );
        }
        if ( %Data &amp;&amp; !$IntroUninstallPost ) {
            my %Data = $Self-&gt;_MessageGet( Info =&gt; $Structure{IntroUninstallPost} );
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'Intro',
                Data =&gt; {
                    %Param,
                    %Data,
                    Subaction =&gt; '',
                    Type      =&gt; 'IntroUninstallPost',
                    Name      =&gt; $Name,
                    Version   =&gt; $Version,
                },
            );
            my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
            $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
            $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
                TemplateFile =&gt; 'AdminPackageManager',
            );
            $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
            return $Output;
        }

        # redirect
        return $Self-&gt;{LayoutObject}-&gt;Redirect( OP =&gt; "Action=$Self-&gt;{Action}" );
    }

    # ------------------------------------------------------------ #
    # install package
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'InstallUpload' ) {

        # challenge token check for write action
        $Self-&gt;{LayoutObject}-&gt;ChallengeTokenCheck();

        my $FormID = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'FormID' ) || '';
        my %UploadStuff = $Self-&gt;{ParamObject}-&gt;GetUploadAll(
            Param =&gt; 'FileUpload',
        );

        # save package in upload cache
        if (%UploadStuff) {
            my $Added = $Self-&gt;{UploadCacheObject}-&gt;FormIDAddFile(
                FormID =&gt; $FormID,
                %UploadStuff,
            );

            # if file got not added to storage
            # (e. g. because of 1 MB max_allowed_packet MySQL problem)
            if ( !$Added ) {
                $Self-&gt;{LayoutObject}-&gt;FatalError();
            }
        }

        # get package from upload cache
        else {
            my @AttachmentData = $Self-&gt;{UploadCacheObject}-&gt;FormIDGetAllFilesData(
                FormID =&gt; $FormID,
            );
            if ( !@AttachmentData || ( $AttachmentData[0] &amp;&amp; !%{ $AttachmentData[0] } ) ) {
                $Errors{FileUploadInvalid} = 'ServerError';
            }
            else {
                %UploadStuff = %{ $AttachmentData[0] };
            }
        }
        if ( !%Errors ) {
            my $Feedback
                = $Self-&gt;{PackageObject}-&gt;PackageIsInstalled( String =&gt; $UploadStuff{Content} );

            if ($Feedback) {
                return $Self-&gt;_UpgradeHandling(
                    Package =&gt; $UploadStuff{Content},
                    FormID  =&gt; $FormID,
                );
            }
            return $Self-&gt;_InstallHandling(
                Package =&gt; $UploadStuff{Content},
                FormID  =&gt; $FormID,
            );
        }
    }

    # ------------------------------------------------------------ #
    # rebuild package
    # ------------------------------------------------------------ #
    elsif ( $Self-&gt;{Subaction} eq 'RebuildPackage' ) {

        # challenge token check for write action
        $Self-&gt;{LayoutObject}-&gt;ChallengeTokenCheck();

        my $Name    = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Name' )    || '';
        my $Version = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'Version' ) || '';

        # get package
        my $Package = $Self-&gt;{PackageObject}-&gt;RepositoryGet(
            Name    =&gt; $Name,
            Version =&gt; $Version,
            Result  =&gt; 'SCALAR',
        );
        if ( !$Package ) {
            return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
        }
        my %Structure = $Self-&gt;{PackageObject}-&gt;PackageParse( String =&gt; $Package, );
        my $File = $Self-&gt;{PackageObject}-&gt;PackageBuild(%Structure);
        return $Self-&gt;{LayoutObject}-&gt;Attachment(
            Content     =&gt; $File,
            ContentType =&gt; 'application/octet-stream',
            Filename    =&gt; "$Name-$Version-rebuild.opm",
            Type        =&gt; 'attachment',
        );
    }

    # ------------------------------------------------------------ #
    # overview
    # ------------------------------------------------------------ #
    my %Frontend;
    my %NeedReinstall;
    my %List;
    my $OutputNotify = '';
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Package::RepositoryList') ) {
        %List = %{ $Self-&gt;{ConfigObject}-&gt;Get('Package::RepositoryList') };
    }
    my %RepositoryRoot;
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Package::RepositoryRoot') ) {
        %RepositoryRoot = $Self-&gt;{PackageObject}-&gt;PackageOnlineRepositories();
    }
    $Frontend{SourceList} = $Self-&gt;{LayoutObject}-&gt;BuildSelection(
        Data =&gt; { %List, %RepositoryRoot, },
        Name =&gt; 'Source',
        Max  =&gt; 40,
        Translation =&gt; 0,
        SelectedID  =&gt; $Source,
        Class       =&gt; "W100pc",
    );
    $Self-&gt;{LayoutObject}-&gt;Block(
        Name =&gt; 'Overview',
        Data =&gt; { %Param, %Frontend, },
    );
    if ($Source) {
        my @List = $Self-&gt;{PackageObject}-&gt;PackageOnlineList(
            URL  =&gt; $Source,
            Lang =&gt; $Self-&gt;{LayoutObject}-&gt;{UserLanguage},
        );
        if ( !@List ) {
            $OutputNotify .= $Self-&gt;{LayoutObject}-&gt;Notify( Priority =&gt; 'Error', );
            if ( !$OutputNotify ) {
                $OutputNotify .= $Self-&gt;{LayoutObject}-&gt;Notify(
                    Priority =&gt; 'Info',
                    Info     =&gt; 'No packages, or no new packages, found in selected repository.',
                );
            }
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'NoDataFoundMsg',
                Data =&gt; {},
            );

        }

        for my $Data (@List) {

            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'ShowRemotePackage',
                Data =&gt; {
                    %{$Data},
                    Source =&gt; $Source,
                },
            );

            # show documentation link
            my %DocFile = $Self-&gt;_DocumentationGet( Filelist =&gt; $Data-&gt;{Filelist} );
            if (%DocFile) {
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'ShowRemotePackageDocumentation',
                    Data =&gt; {
                        %{$Data},
                        Source =&gt; $Source,
                        %DocFile,
                    },
                );
            }

            if ( $Data-&gt;{Upgrade} ) {
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'ShowRemotePackageUpgrade',
                    Data =&gt; { %{$Data}, Source =&gt; $Source, },
                );
            }
            elsif ( !$Data-&gt;{Installed} ) {
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'ShowRemotePackageInstall',
                    Data =&gt; { %{$Data}, Source =&gt; $Source, },
                );
            }
        }
    }

    # if there are no remote packages to show, a msg is displayed
    else {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'NoDataFoundMsg',
            Data =&gt; {},
        );
    }

    my @RepositoryList = $Self-&gt;{PackageObject}-&gt;RepositoryList();

    # if there are no local packages to show, a msg is displayed
    if ( !@RepositoryList ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'NoDataFoundMsg2',
        );
    }

    # verify packages if we have some
    my %VerificationData;
    if (@RepositoryList) {
        %VerificationData = $Self-&gt;{PackageObject}-&gt;PackageVerifyAll();
    }

    my %NotVerifiedPackages;
    for my $Package (@RepositoryList) {

        my %Data = $Self-&gt;_MessageGet( Info =&gt; $Package-&gt;{Description} );

        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'ShowLocalPackage',
            Data =&gt; {
                %{$Package},
                %Data,
                Name    =&gt; $Package-&gt;{Name}-&gt;{Content},
                Version =&gt; $Package-&gt;{Version}-&gt;{Content},
                Vendor  =&gt; $Package-&gt;{Vendor}-&gt;{Content},
                URL     =&gt; $Package-&gt;{URL}-&gt;{Content},
            },
        );

        if (
            $VerificationData{ $Package-&gt;{Name}-&gt;{Content} }
            &amp;&amp; $VerificationData{ $Package-&gt;{Name}-&gt;{Content} } eq 'verified'
            )
        {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'ShowLocalPackageVerifyLogo',
            );
        }

        # show documentation link
        my %DocFile = $Self-&gt;_DocumentationGet( Filelist =&gt; $Package-&gt;{Filelist} );
        if (%DocFile) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'ShowLocalPackageDocumentation',
                Data =&gt; {
                    Name    =&gt; $Package-&gt;{Name}-&gt;{Content},
                    Version =&gt; $Package-&gt;{Version}-&gt;{Content},
                    %DocFile,
                },
            );
        }

        if ( $Package-&gt;{Status} eq 'installed' ) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'ShowLocalPackageUninstall',
                Data =&gt; {
                    %{$Package},
                    Name    =&gt; $Package-&gt;{Name}-&gt;{Content},
                    Version =&gt; $Package-&gt;{Version}-&gt;{Content},
                    Vendor  =&gt; $Package-&gt;{Vendor}-&gt;{Content},
                    URL     =&gt; $Package-&gt;{URL}-&gt;{Content},
                },
            );
            if (
                !$Self-&gt;{PackageObject}-&gt;DeployCheck(
                    Name    =&gt; $Package-&gt;{Name}-&gt;{Content},
                    Version =&gt; $Package-&gt;{Version}-&gt;{Content}
                )
                )
            {
                $NeedReinstall{ $Package-&gt;{Name}-&gt;{Content} } = $Package-&gt;{Version}-&gt;{Content};
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'ShowLocalPackageReinstall',
                    Data =&gt; {
                        %{$Package},
                        Name    =&gt; $Package-&gt;{Name}-&gt;{Content},
                        Version =&gt; $Package-&gt;{Version}-&gt;{Content},
                        Vendor  =&gt; $Package-&gt;{Vendor}-&gt;{Content},
                        URL     =&gt; $Package-&gt;{URL}-&gt;{Content},
                    },
                );
            }
        }
        else {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'ShowLocalPackageInstall',
                Data =&gt; {
                    %{$Package},
                    Name    =&gt; $Package-&gt;{Name}-&gt;{Content},
                    Version =&gt; $Package-&gt;{Version}-&gt;{Content},
                    Vendor  =&gt; $Package-&gt;{Vendor}-&gt;{Content},
                    URL     =&gt; $Package-&gt;{URL}-&gt;{Content},
                },
            );
        }

        if (
            $VerificationData{ $Package-&gt;{Name}-&gt;{Content} }
            &amp;&amp; $VerificationData{ $Package-&gt;{Name}-&gt;{Content} } eq 'not_verified'
            )
        {
            $NotVerifiedPackages{ $Package-&gt;{Name}-&gt;{Content} } = $Package-&gt;{Version}-&gt;{Content};
        }
    }

    # show file upload
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Package::FileUpload') ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'OverviewFileUpload',
            Data =&gt; {
                FormID =&gt; $Self-&gt;{UploadCacheObject}-&gt;FormIDCreate(),
                %Errors,
            },
        );

        # check if we're on MySQL and show a max_allowed_packet notice
        # if the actual value for this setting is too low
        if ( $Self-&gt;{DBObject}-&gt;{'DB::Type'} eq 'mysql' ) {

            # check the actual setting
            $Self-&gt;{DBObject}-&gt;Prepare(
                SQL =&gt; "SHOW variables WHERE Variable_name = 'max_allowed_packet'",
            );

            my $MaxAllowedPacket            = 0;
            my $MaxAllowedPacketRecommended = 20;
            while ( my @Data = $Self-&gt;{DBObject}-&gt;FetchrowArray() ) {
                if ( $Data[1] ) {
                    $MaxAllowedPacket = $Data[1] / 1024 / 1024;
                }
            }

            if ( $MaxAllowedPacket &lt; $MaxAllowedPacketRecommended ) {
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'DatabasePackageSizeWarning',
                    Data =&gt; {
                        MaxAllowedPacket            =&gt; $MaxAllowedPacket,
                        MaxAllowedPacketRecommended =&gt; $MaxAllowedPacketRecommended,
                    },
                );
            }
        }
    }

    # FeatureAddons
    if ( $Self-&gt;{ConfigObject}-&gt;Get('Package::ShowFeatureAddons') ) {
        my $FeatureAddonData = $Self-&gt;_GetFeatureAddonData();

        if ( ref $FeatureAddonData eq 'ARRAY' &amp;&amp; scalar @{$FeatureAddonData} &gt; 0 ) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'FeatureAddonList',
            );

            for my $Item ( @{$FeatureAddonData} ) {
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'FeatureAddonData',
                    Data =&gt; $Item,
                );
            }
        }
    }

    my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
    $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
    $Output .= $OutputNotify;
    for my $ReinstallKey ( sort keys %NeedReinstall ) {
        $Output .= $Self-&gt;{LayoutObject}-&gt;Notify(
            Priority =&gt; 'Error',
            Data     =&gt; "$ReinstallKey $NeedReinstall{$ReinstallKey}"
                . ' - $Text{"Package not correctly deployed! Please reinstall the package."}',
            Link =&gt; '$Env{"Baselink"}Action=$Env{"Action"};Subaction=View;Name='
                . $ReinstallKey
                . ';Version='
                . $NeedReinstall{$ReinstallKey},
        );
    }

    VERIFICATION:
    for my $Package ( sort keys %NotVerifiedPackages ) {

        next VERIFICATION if !$Package;
        next VERIFICATION if !$NotVerifiedPackages{$Package};

        $Output .= $Self-&gt;{LayoutObject}-&gt;Notify(
            Priority =&gt; 'Error',
            Data     =&gt; "$Package $NotVerifiedPackages{$Package} - "
                . '$Text{"Package not verified by the OTRS Group! It is recommended not to use this package."}',
        );
    }

    $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
        TemplateFile =&gt; 'AdminPackageManager',
    );
    $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
    return $Output;
}

sub _MessageGet {
    my ( $Self, %Param ) = @_;

    my $Title       = '';
    my $Description = '';
    my $Use         = 0;

    my $Language = $Self-&gt;{LayoutObject}-&gt;{UserLanguage}
        || $Self-&gt;{ConfigObject}-&gt;Get('DefaultLanguage');

    if ( $Param{Info} ) {
        for my $Tag ( @{ $Param{Info} } ) {
            if ( $Param{Type} ) {
                next if $Tag-&gt;{Type} !~ /^$Param{Type}/i;
            }
            $Use = 1;
            if ( $Tag-&gt;{Format} &amp;&amp; $Tag-&gt;{Format} =~ /plain/i ) {
                $Tag-&gt;{Content} = '&lt;pre class="contentbody"&gt;' . $Tag-&gt;{Content} . '&lt;/pre&gt;';
            }
            if ( !$Description &amp;&amp; $Tag-&gt;{Lang} eq 'en' ) {
                $Description = $Tag-&gt;{Content};
                $Title       = $Tag-&gt;{Title};
            }

            if ( $Tag-&gt;{Lang} eq $Language ) {
                $Description = $Tag-&gt;{Content};
                $Title       = $Tag-&gt;{Title};
            }
        }
        if ( !$Description &amp;&amp; $Use ) {
            for my $Tag ( @{ $Param{Info} } ) {
                if ( !$Description ) {
                    $Description = $Tag-&gt;{Content};
                    $Title       = $Tag-&gt;{Title};
                }
            }
        }
    }
    return if !$Description &amp;&amp; !$Title;
    return (
        Description =&gt; $Description,
        Title       =&gt; $Title,
    );
}

sub _DocumentationGet {
    my ( $Self, %Param ) = @_;

    return if !$Param{Filelist};
    return if ref $Param{Filelist} ne 'ARRAY';

    # find the correct user language documentation file
    my $DocumentationFileUserLanguage;

    # find the correct default language documentation file
    my $DocumentationFileDefaultLanguage;

    # find the correct en documentation file
    my $DocumentationFile;

    # remember fallback file
    my $DocumentationFileFallback;

    # get default language
    my $DefaultLanguage = $Self-&gt;{ConfigObject}-&gt;Get('DefaultLanguage');

    # find documentation files
    FILE:
    for my $File ( @{ $Param{Filelist} } ) {

        next FILE if !$File;
        next FILE if !$File-&gt;{Location};

        my ( $Dir, $Filename ) = $File-&gt;{Location} =~ m{ \A doc/ ( .+ ) / ( .+? .pdf ) }xmsi;

        next FILE if !$Dir;
        next FILE if !$Filename;

        # take user language first
        if ( $Dir eq $Self-&gt;{LayoutObject}-&gt;{UserLanguage} ) {
            $DocumentationFileUserLanguage = $File-&gt;{Location};
        }

        # take default language next
        elsif ( $Dir eq $DefaultLanguage ) {
            $DocumentationFileDefaultLanguage = $File-&gt;{Location};
        }

        # take en language next
        elsif ( $Dir eq 'en' &amp;&amp; !$DocumentationFile ) {
            $DocumentationFile = $File-&gt;{Location};
        }

        # remember fallback file
        $DocumentationFileFallback = $File-&gt;{Location};
    }

    # set fallback file (if exists) as documentation file
    my %Doc;
    if ($DocumentationFileUserLanguage) {
        $Doc{Location} = $DocumentationFileUserLanguage;
    }
    elsif ($DocumentationFileDefaultLanguage) {
        $Doc{Location} = $DocumentationFileDefaultLanguage;
    }
    elsif ($DocumentationFile) {
        $Doc{Location} = $DocumentationFile;
    }
    elsif ($DocumentationFileFallback) {
        $Doc{Location} = $DocumentationFileFallback;
    }
    return %Doc;
}

sub _InstallHandling {
    my ( $Self, %Param ) = @_;

    # check needed params
    if ( !$Param{Package} ) {
        return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
    }

    # redirect after finishing installation
    if ( $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'IntroInstallPost' ) ) {
        return $Self-&gt;{LayoutObject}-&gt;Redirect( OP =&gt; "Action=$Self-&gt;{Action}" );
    }

    my $IntroInstallPre    = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'IntroInstallPre' )    || '';
    my $IntroInstallVendor = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'IntroInstallVendor' ) || '';

    # parse package
    my %Structure = $Self-&gt;{PackageObject}-&gt;PackageParse( String =&gt; $Param{Package} );

    # online verification
    my $Verified = $Self-&gt;{PackageObject}-&gt;PackageVerify(
        Package   =&gt; $Param{Package},
        Structure =&gt; \%Structure,
    ) || 'verified';
    my %VerifyInfo = $Self-&gt;{PackageObject}-&gt;PackageVerifyInfo();

    # translate description
    if ( $Self-&gt;{LayoutObject}-&gt;{LanguageObject} ) {
        $VerifyInfo{Description} = $Self-&gt;{LayoutObject}-&gt;{LanguageObject}-&gt;Get(
            $VerifyInfo{Description}
        );
    }

    # vendor screen
    if ( !$IntroInstallVendor &amp;&amp; !$IntroInstallPre &amp;&amp; $Verified ne 'verified' ) {

        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Intro',
            Data =&gt; {
                %Param,
                %VerifyInfo,
                Subaction =&gt; $Self-&gt;{Subaction},
                Type      =&gt; 'IntroInstallVendor',
                Name      =&gt; $Structure{Name}-&gt;{Content},
                Version   =&gt; $Structure{Version}-&gt;{Content},
            },
        );

        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'IntroCancel',
        );

        my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
        $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
        $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
            TemplateFile =&gt; 'AdminPackageManager',
        );
        $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
        return $Output;
    }

    # intro screen
    my %Data;
    if ( $Structure{IntroInstall} ) {
        %Data = $Self-&gt;_MessageGet( Info =&gt; $Structure{IntroInstall}, Type =&gt; 'pre' );
    }

    # intro before installation
    if ( %Data &amp;&amp; !$IntroInstallPre ) {

        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Intro',
            Data =&gt; {
                %Param,
                %Data,
                Subaction =&gt; $Self-&gt;{Subaction},
                Type      =&gt; 'IntroInstallPre',
                Name      =&gt; $Structure{Name}-&gt;{Content},
                Version   =&gt; $Structure{Version}-&gt;{Content},
            },
        );

        if ( $Verified eq 'verified' ) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'OTRSVerifyLogo',
            );
        }

        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'IntroCancel',
        );
        my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
        $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
        $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
            TemplateFile =&gt; 'AdminPackageManager',
        );
        $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
        return $Output;
    }

    # install package
    elsif ( $Self-&gt;{PackageObject}-&gt;PackageInstall( String =&gt; $Param{Package} ) ) {

        # intro screen
        my %Data;
        if ( $Structure{IntroInstall} ) {
            %Data = $Self-&gt;_MessageGet( Info =&gt; $Structure{IntroInstall}, Type =&gt; 'post' );
        }
        if (%Data) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'Intro',
                Data =&gt; {
                    %Param,
                    %Data,
                    Subaction =&gt; 'Install',
                    Type      =&gt; 'IntroInstallPost',
                    Name      =&gt; $Structure{Name}-&gt;{Content},
                    Version   =&gt; $Structure{Version}-&gt;{Content},
                },
            );

            if ( $Verified eq 'verified' ) {
                $Self-&gt;{LayoutObject}-&gt;Block(
                    Name =&gt; 'OTRSVerifyLogo',
                );
            }

            my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
            $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
            $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
                TemplateFile =&gt; 'AdminPackageManager',
            );
            $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
            return $Output;
        }

        # redirect
        return $Self-&gt;{LayoutObject}-&gt;Redirect( OP =&gt; "Action=$Self-&gt;{Action}" );
    }

    return $Self-&gt;{LayoutObject}-&gt;ErrorScreen();
}

sub _UpgradeHandling {
    my ( $Self, %Param ) = @_;

    # check needed params
    if ( !$Param{Package} ) {
        return $Self-&gt;{LayoutObject}-&gt;ErrorScreen( Message =&gt; 'No such package!' );
    }

    # redirect after finishing upgrade
    if ( $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'IntroUpgradePost' ) ) {
        return $Self-&gt;{LayoutObject}-&gt;Redirect( OP =&gt; "Action=$Self-&gt;{Action}" );
    }

    my $IntroUpgradePre = $Self-&gt;{ParamObject}-&gt;GetParam( Param =&gt; 'IntroUpgradePre' ) || '';

    # check if we have to show upgrade intro pre
    my %Structure = $Self-&gt;{PackageObject}-&gt;PackageParse( String =&gt; $Param{Package}, );

    # intro screen
    my %Data;
    if ( $Structure{IntroUpgrade} ) {
        %Data = $Self-&gt;_MessageGet( Info =&gt; $Structure{IntroUpgrade}, Type =&gt; 'pre' );
    }
    if ( %Data &amp;&amp; !$IntroUpgradePre ) {
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'Intro',
            Data =&gt; {
                %Param,
                %Data,
                Subaction =&gt; $Self-&gt;{Subaction},
                Type      =&gt; 'IntroUpgradePre',
                Name      =&gt; $Structure{Name}-&gt;{Content},
                Version   =&gt; $Structure{Version}-&gt;{Content},
            },
        );
        $Self-&gt;{LayoutObject}-&gt;Block(
            Name =&gt; 'IntroCancel',
        );
        my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
        $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
        $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
            TemplateFile =&gt; 'AdminPackageManager',
        );
        $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
        return $Output;
    }

    # upgrade
    elsif ( $Self-&gt;{PackageObject}-&gt;PackageUpgrade( String =&gt; $Param{Package} ) ) {

        # intro screen
        my %Data;
        if ( $Structure{IntroUpgrade} ) {
            %Data = $Self-&gt;_MessageGet( Info =&gt; $Structure{IntroUpgrade}, Type =&gt; 'post' );
        }
        if (%Data) {
            $Self-&gt;{LayoutObject}-&gt;Block(
                Name =&gt; 'Intro',
                Data =&gt; {
                    %Param,
                    %Data,
                    Subaction =&gt; '',
                    Type      =&gt; 'IntroUpgradePost',
                    Name      =&gt; $Structure{Name}-&gt;{Content},
                    Version   =&gt; $Structure{Version}-&gt;{Content},
                },
            );
            my $Output = $Self-&gt;{LayoutObject}-&gt;Header();
            $Output .= $Self-&gt;{LayoutObject}-&gt;NavigationBar();
            $Output .= $Self-&gt;{LayoutObject}-&gt;Output(
                TemplateFile =&gt; 'AdminPackageManager',
            );
            $Output .= $Self-&gt;{LayoutObject}-&gt;Footer();
            return $Output;
        }

        # redirect
        return $Self-&gt;{LayoutObject}-&gt;Redirect( OP =&gt; "Action=$Self-&gt;{Action}" );
    }

    return $Self-&gt;{LayoutObject}-&gt;ErrorScreen();
}

sub _GetFeatureAddonData {
    my ( $Self, %Param ) = @_;

    # Default URL
    my $FeedURL = 'http://www.otrs.com/feed/?post_type=feature_add_ons&amp;lang=en';

    my $Language = $Self-&gt;{LayoutObject}-&gt;{UserLanguage};

    # Check if URL for UserLanguage is available
    if ( $Language =~ m/^de/ ) {
        $FeedURL = 'http://www.otrs.com/feed/?post_type=feature_add_ons&amp;lang=de';
    }

    if ( $Language =~ m/^es/ ) {
        $FeedURL = 'http://www.otrs.com/feed/?post_type=feature_add_ons&amp;lang=es';
    }

    my $CacheKey  = "FeatureAddonData::$FeedURL";
    my $CacheTTL  = 60 * 60 * 24;                   # 1 day
    my $CacheType = 'PackageManager';

    my $CacheResult = $Self-&gt;{CacheObject}-&gt;Get(
        Type =&gt; $CacheType,
        Key  =&gt; $CacheKey,
    );

    return $CacheResult if ref $CacheResult eq 'ARRAY';

    # set proxy settings can't use Kernel::System::WebAgent because of used
    # XML::FeedPP to get RSS files
    my $Proxy = $Self-&gt;{ConfigObject}-&gt;Get('WebUserAgent::Proxy');
    if ($Proxy) {
        $ENV{CGI_HTTP_PROXY} = $Proxy;
    }

    # get content
    my $Feed = eval {
        XML::FeedPP-&gt;new(
            $FeedURL,
            'xml_deref' =&gt; 1,
            'utf8_flag' =&gt; 1,
        );
    };

    return if !$Feed;

    my @Result;
    my $Count = 0;
    ITEM:
    for my $Item ( $Feed-&gt;get_item() ) {
        $Count++;
        last ITEM if $Count &gt; 100;

        push @Result, {
            Title       =&gt; $Item-&gt;title(),
            Link        =&gt; $Item-&gt;link(),
            Description =&gt; $Item-&gt;get('content:encoded'),
        };
    }

    # set cache
    $Self-&gt;{CacheObject}-&gt;Set(
        Type  =&gt; $CacheType,
        Key   =&gt; $CacheKey,
        Value =&gt; \@Result,
        TTL   =&gt; $CacheTTL,
    );

    return \@Result;
}

1;
</pre></body></html>