###############################################################################
# #
# IPFire.org - A linux based firewall #
-# Copyright (C) 2007-2011 Michael Tremer & Christian Schmidt #
+# Copyright (C) 2007-2022 IPFire Team <info@ipfire.org> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
###############################################################################
use strict;
+use List::Util qw(any);
+use URI;
# enable only the following on debugging purpose
#use warnings;
require "${General::swroot}/header.pl";
require "/opt/pakfire/lib/functions.pl";
-my %pakfiresettings=();
+my %cgiparams=();
my $errormessage = '';
my %color = ();
+my %pakfiresettings = ();
my %mainsettings = ();
-&Header::showhttpheaders();
+# The page mode is used to explictly switch between user interface functions:
+my $PM_DEFAULT = 'default'; # Default user interface with command processing
+my $PM_LOGREAD = 'logread'; # Log messages viewer (ignores all commands)
+my $pagemode = $PM_DEFAULT;
-$pakfiresettings{'ACTION'} = '';
-$pakfiresettings{'VALID'} = '';
+# Get Pakfire status
+my %pakfire_status = &Pakfire::status();
-$pakfiresettings{'INSPAKS'} = '';
-$pakfiresettings{'DELPAKS'} = '';
-$pakfiresettings{'AUTOUPDATE'} = 'off';
-$pakfiresettings{'HEALTHCHECK'} = 'on';
-$pakfiresettings{'UUID'} = 'on';
+# Load general settings
+&General::readhash("${General::swroot}/main/settings", \%mainsettings);
+&General::readhash("${General::swroot}/pakfire/settings", \%pakfiresettings);
+&General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt", \%color);
-sub refreshpage{&Header::openbox( 'Waiting', 1, "<meta http-equiv='refresh' content='1;'>" );print "<center><img src='/images/clock.gif' alt='' /><br/><font color='red'>$Lang::tr{'pagerefresh'}</font></center>";&Header::closebox();}
+# Get CGI POST request data
+$cgiparams{'ACTION'} = '';
+$cgiparams{'FORCE'} = '';
-&Header::getcgihash(\%pakfiresettings);
+$cgiparams{'INSPAKS'} = '';
+$cgiparams{'DELPAKS'} = '';
-&General::readhash("${General::swroot}/main/settings", \%mainsettings);
-&General::readhash("/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color);
+&Header::getcgihash(\%cgiparams);
-&Header::openpage($Lang::tr{'pakfire configuration'}, 1);
-&Header::openbigbox('100%', 'left', '', $errormessage);
+# Get CGI GET request data (if available)
+if($ENV{'QUERY_STRING'}) {
+ my $uri = URI->new($ENV{'REQUEST_URI'});
+ my %query = $uri->query_form;
-if ($pakfiresettings{'ACTION'} eq 'install'){
- $pakfiresettings{'INSPAKS'} =~ s/\|/\ /g;
- if ("$pakfiresettings{'FORCE'}" eq "on") {
- my $command = "/usr/local/bin/pakfire install --non-interactive --no-colors $pakfiresettings{'INSPAKS'} &>/dev/null &";
- system("$command");
- system("/bin/sleep 1");
- } else {
- &Header::openbox("100%", "center", $Lang::tr{'request'});
- my @output = `/usr/local/bin/pakfire resolvedeps --no-colors $pakfiresettings{'INSPAKS'}`;
- print <<END;
- <table><tr><td colspan='2'>$Lang::tr{'pakfire install package'}.$pakfiresettings{'INSPAKS'}.$Lang::tr{'pakfire possible dependency'}
- <pre>
-END
- foreach (@output) {
- $_ =~ s/\\e\[[0-1]\;[0-9]+m//g;
- print "$_\n";
- }
- print <<END;
- </pre>
- <tr><td colspan='2'>$Lang::tr{'pakfire accept all'}
- <tr><td colspan='2'>
- <tr><td align='right'><form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <input type='hidden' name='INSPAKS' value='$pakfiresettings{'INSPAKS'}' />
- <input type='hidden' name='FORCE' value='on' />
- <input type='hidden' name='ACTION' value='install' />
- <input type='image' alt='$Lang::tr{'install'}' src='/images/go-next.png' />
- </form>
- <td align='left'>
- <form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <input type='hidden' name='ACTION' value='' />
- <input type='image' alt='$Lang::tr{'abort'}' src='/images/dialog-error.png' />
- </form>
- </table>
-END
- &Header::closebox();
- &Header::closebigbox();
- &Header::closepage();
- exit;
+ my $mode = lc($query{'mode'} // '');
+ if(($mode eq $PM_DEFAULT) || ($mode eq $PM_LOGREAD)) {
+ $pagemode = $mode; # Limit to existing modes
}
-} elsif ($pakfiresettings{'ACTION'} eq 'remove') {
-
- $pakfiresettings{'DELPAKS'} =~ s/\|/\ /g;
- if ("$pakfiresettings{'FORCE'}" eq "on") {
- my $command = "/usr/local/bin/pakfire remove --non-interactive --no-colors $pakfiresettings{'DELPAKS'} &>/dev/null &";
- system("$command");
- system("/bin/sleep 1");
- } else {
- &Header::openbox("100%", "center", $Lang::tr{'request'});
- my @output = `/usr/local/bin/pakfire resolvedeps --no-colors $pakfiresettings{'DELPAKS'}`;
- print <<END;
- <table><tr><td colspan='2'>$Lang::tr{'pakfire uninstall package'}.$pakfiresettings{'DELPAKS'}.$Lang::tr{'pakfire possible dependency'}
- <pre>
-END
- foreach (@output) {
- $_ =~ s/\\e\[[0-1]\;[0-9]+m//g;
- print "$_\n";
+}
+
+### Process AJAX/JSON request ###
+if($cgiparams{'ACTION'} eq 'json-getstatus') {
+ # Send HTTP headers
+ _start_json_output();
+
+ # Read /var/log/messages backwards until a "Pakfire started" header is found,
+ # to capture all messages of the last (i.e. current) Pakfire run
+ my @messages = `tac /var/log/messages 2>/dev/null | sed -n '/pakfire:/{p;/Pakfire.*started/q}'`;
+
+ # Test if the log contains an error message (fastest implementation, stops at first match)
+ my $failure = any{ index($_, 'ERROR') != -1 } @messages;
+
+ # Collect Pakfire status
+ my %status = (
+ 'running' => &_is_pakfire_busy() || "0",
+ 'running_since' => &General::age("$Pakfire::lockfile") || "0s",
+ 'reboot' => ("$pakfire_status{'RebootRequired'}" eq "yes") || "0",
+ 'failure' => $failure || "0"
+ );
+
+ # Start JSON file
+ print "{\n";
+
+ foreach my $key (keys %status) {
+ my $value = $status{$key};
+ print qq{\t"$key": "$value",\n};
+ }
+
+ # Print sanitized messages in reverse order to undo previous "tac"
+ print qq{\t"messages": [\n};
+ for my $index (reverse (0 .. $#messages)) {
+ my $line = $messages[$index];
+ $line =~ s/[[:cntrl:]<>&\\]+//g;
+
+ print qq{\t\t"$line"};
+ print ",\n" unless $index < 1;
+ }
+ print "\n\t]\n";
+
+ # Finalize JSON file & stop
+ print "}";
+ exit;
+}
+
+### Process Pakfire install/update commands ###
+if(($cgiparams{'ACTION'} ne '') && ($pagemode eq $PM_DEFAULT)) {
+ if(&_is_pakfire_busy()) {
+ $errormessage = $Lang::tr{'pakfire already busy'};
+ $pagemode = $PM_LOGREAD; # Running Pakfire instance found, switch to log viewer mode
+ } elsif(($cgiparams{'ACTION'} eq 'install') && ($cgiparams{'FORCE'} eq 'on')) {
+ my @pkgs = split(/\|/, $cgiparams{'INSPAKS'});
+ &General::system_background("/usr/local/bin/pakfire", "install", "--non-interactive", "--no-colors", @pkgs);
+ &_http_pagemode_redirect($PM_LOGREAD, 1);
+ } elsif(($cgiparams{'ACTION'} eq 'remove') && ($cgiparams{'FORCE'} eq 'on')) {
+ my @pkgs = split(/\|/, $cgiparams{'DELPAKS'});
+ &General::system_background("/usr/local/bin/pakfire", "remove", "--non-interactive", "--no-colors", @pkgs);
+ &_http_pagemode_redirect($PM_LOGREAD, 1);
+ } elsif($cgiparams{'ACTION'} eq 'update') {
+ &General::system_background("/usr/local/bin/pakfire", "update", "--force", "--no-colors");
+ &_http_pagemode_redirect($PM_LOGREAD, 1);
+ } elsif($cgiparams{'ACTION'} eq 'upgrade') {
+ &General::system_background("/usr/local/bin/pakfire", "upgrade", "-y", "--no-colors");
+ &_http_pagemode_redirect($PM_LOGREAD, 1);
+ } elsif($cgiparams{'ACTION'} eq $Lang::tr{'save'}) {
+ $pakfiresettings{"TREE"} = $cgiparams{"TREE"};
+
+ # Check for valid input
+ if ($pakfiresettings{"TREE"} !~ m/^(stable|testing|unstable)$/) {
+ $errormessage .= $Lang::tr{'pakfire invalid tree'};
+ }
+
+ unless ($errormessage) {
+ &General::writehash("${General::swroot}/pakfire/settings", \%pakfiresettings);
+
+ # Update lists
+ &General::system_background("/usr/local/bin/pakfire", "update", "--force", "--no-colors");
+ &_http_pagemode_redirect($PM_LOGREAD, 1);
}
- print <<END;
- </pre>
- <tr><td colspan='2'>$Lang::tr{'pakfire accept all'}
- <tr><td colspan='2'>
- <tr><td align='right'><form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <input type='hidden' name='DELPAKS' value='$pakfiresettings{'DELPAKS'}' />
- <input type='hidden' name='FORCE' value='on' />
- <input type='hidden' name='ACTION' value='remove' />
- <input type='image' alt='$Lang::tr{'uninstall'}' src='/images/go-next.png' />
- </form>
- <td align='left'>
- <form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <input type='hidden' name='ACTION' value='' />
- <input type='image' alt='$Lang::tr{'abort'}' src='/images/dialog-error.png' />
- </form>
- </table>
-END
- &Header::closebox();
- &Header::closebigbox();
- &Header::closepage();
- exit;
}
+}
-} elsif ($pakfiresettings{'ACTION'} eq 'update') {
+### Start pakfire page ###
+&Header::showhttpheaders();
- system("/usr/local/bin/pakfire update --force --no-colors &>/dev/null &");
- system("/bin/sleep 1");
-} elsif ($pakfiresettings{'ACTION'} eq 'upgrade') {
- my $command = "/usr/local/bin/pakfire upgrade -y --no-colors &>/dev/null &";
- system("$command");
- system("/bin/sleep 1");
-} elsif ($pakfiresettings{'ACTION'} eq "$Lang::tr{'save'}") {
+###--- HTML HEAD ---###
+my $extraHead = <<END
+<style>
+ /* Main screen */
+ table#pfmain {
+ width: 100%;
+ border-style: hidden;
+ table-layout: fixed;
+ }
- if ($pakfiresettings{'AUTOUPDATE'} eq 'on') {
- system("/usr/local/bin/pakfire enable updates >/dev/null 2>&1");
- } else {
- system("/usr/local/bin/pakfire disable updates >/dev/null 2>&1");
+ #pfmain td {
+ padding: 5px 20px 0;
+ text-align: center;
+ }
+ #pfmain tr:not(:last-child) > td {
+ padding-bottom: 1.5em;
+ }
+ #pfmain tr > td.heading {
+ padding: 0;
+ font-weight: bold;
+ background-color: $color{'color20'};
}
- &General::writehash("${General::swroot}/pakfire/settings", \%pakfiresettings);
-}
+ .pflist {
+ width: 100%;
+ text-align: left;
+ margin-bottom: 0.8em;
+ }
-&General::readhash("${General::swroot}/pakfire/settings", \%pakfiresettings);
+ /* Pakfire log viewer */
+ section#pflog-header {
+ width: 100%;
+ display: flex;
+ text-align: left;
+ align-items: center;
+ column-gap: 20px;
+ }
+ #pflog-header > div:last-child {
+ margin-left: auto;
+ margin-right: 20px;
+ }
+ #pflog-header span {
+ line-height: 1.3em;
+ }
+ #pflog-header span:empty::before {
+ content: "\\200b"; /* zero width space */
+ }
-my %selected=();
-my %checked=();
+ pre#pflog-messages {
+ margin-top: 0.7em;
+ padding-top: 0.7em;
+ border-top: 0.5px solid $Header::bordercolour;
+
+ text-align: left;
+ min-height: 15em;
+ overflow-x: auto;
+ }
+</style>
+
+<script src="/include/pakfire.js"></script>
+<script>
+ // Translations
+ pakfire.i18n.load({
+ 'working': '$Lang::tr{'pakfire working'}',
+ 'finished': '$Lang::tr{'pakfire finished'}',
+ 'finished error': '$Lang::tr{'pakfire finished error'}',
+ 'since': '$Lang::tr{'since'}',
+
+ 'link_return': '<a href="$ENV{'SCRIPT_NAME'}">$Lang::tr{'pakfire return'}</a>',
+ 'link_reboot': '<a href="/cgi-bin/shutdown.cgi">$Lang::tr{'needreboot'}</a>'
+ });
+
+ // AJAX auto refresh interval (in ms, default: 1000)
+ //pakfire.refreshInterval = 1000;
+
+ // Enable returning to main screen (delay in ms)
+ pakfire.setupPageReload(true, 3000);
+</script>
+END
+;
+###--- END HTML HEAD ---###
+
+&Header::openpage($Lang::tr{'pakfire configuration'}, 1, $extraHead);
+&Header::openbigbox('100%', 'left', '', $errormessage);
-$checked{'AUTOUPDATE'}{'off'} = '';
-$checked{'AUTOUPDATE'}{'on'} = '';
-$checked{'AUTOUPDATE'}{$pakfiresettings{'AUTOUPDATE'}} = "checked='checked'";
-$checked{'HEALTHCHECK'}{'off'} = '';
-$checked{'HEALTHCHECK'}{'on'} = '';
-$checked{'HEALTHCHECK'}{$pakfiresettings{'HEALTHCHECK'}} = "checked='checked'";
-$checked{'UUID'}{'off'} = '';
-$checked{'UUID'}{'on'} = '';
-$checked{'UUID'}{$pakfiresettings{'UUID'}} = "checked='checked'";
-
-# DPC move error message to top so it is seen!
+# Show error message
if ($errormessage) {
&Header::openbox('100%', 'left', $Lang::tr{'error messages'});
print "<font class='base'>$errormessage </font>\n";
&Header::closebox();
}
-my $return = `pidof pakfire`;
-chomp($return);
-if ($return) {
- &Header::openbox( 'Waiting', 1, "<meta http-equiv='refresh' content='10;'>" );
+# Show only log output while Pakfire is running and stop afterwards
+if(($pagemode eq $PM_LOGREAD) || (&_is_pakfire_busy())) {
+ &Header::openbox("100%", "center", "Pakfire");
+
+ print <<END
+<section id="pflog-header">
+ <div><img src="/images/indicator.gif" alt="$Lang::tr{'active'}" title="$Lang::tr{'pagerefresh'}"></div>
+ <div>
+ <span id="pflog-status">$Lang::tr{'pakfire working'}</span><br>
+ <span id="pflog-time"></span><br>
+ <span id="pflog-action"></span>
+ </div>
+ <div><a href="$ENV{'SCRIPT_NAME'}"><img src="/images/view-refresh.png" alt="$Lang::tr{'refresh'}" title="$Lang::tr{'refresh'}"></a></div>
+</section>
+
+<!-- Pakfire log messages -->
+<pre id="pflog-messages"></pre>
+<script>
+ // Start automatic log refresh
+ pakfire.running = true;
+</script>
+
+END
+;
+
+ &Header::closebox();
+ &Header::closebigbox();
+ &Header::closepage();
+ exit;
+}
+
+# Show Pakfire install/remove dependencies and confirm form
+# (_is_pakfire_busy status was checked before and can be omitted)
+if (($cgiparams{'ACTION'} eq 'install') && ($pagemode eq $PM_DEFAULT)) {
+ &Header::openbox("100%", "center", $Lang::tr{'request'});
+
+ my @pkgs = split(/\|/, $cgiparams{'INSPAKS'});
+ my @output = &General::system_output("/usr/local/bin/pakfire", "resolvedeps", "--no-colors", @pkgs);
print <<END;
- <table>
- <tr><td>
- <img src='/images/indicator.gif' alt='$Lang::tr{'aktiv'}' />
- <td>
- $Lang::tr{'pakfire working'}
- <tr><td colspan='2' align='center'>
- <form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <input type='image' alt='$Lang::tr{'reload'}' src='/images/view-refresh.png' />
- </form>
- <tr><td colspan='2' align='left'><pre>
+ <table style="width: 100%"><tr><td colspan='2'><p>$Lang::tr{'pakfire install package'} <strong>@{pkgs}</strong><br>
+ $Lang::tr{'pakfire possible dependency'}</p>
+ <pre>
END
- my @output = `grep pakfire /var/log/messages | tail -20`;
foreach (@output) {
- print "$_";
+ $_ =~ s/\\e\[[0-1]\;[0-9]+m//g;
+ print "$_\n";
}
print <<END;
- </pre>
- </table>
+ </pre></td></tr>
+ <tr><td colspan='2'>$Lang::tr{'pakfire accept all'}</td></tr>
+ <tr><td colspan='2'> </td></tr>
+ <tr><td align='right'><form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <input type='hidden' name='INSPAKS' value='$cgiparams{'INSPAKS'}' />
+ <input type='hidden' name='FORCE' value='on' />
+ <input type='hidden' name='ACTION' value='install' />
+ <input type='image' alt='$Lang::tr{'install'}' title='$Lang::tr{'install'}' src='/images/go-next.png' />
+ </form>
+ </td>
+ <td align='left'>
+ <form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <input type='hidden' name='ACTION' value='' />
+ <input type='image' alt='$Lang::tr{'abort'}' title='$Lang::tr{'abort'}' src='/images/dialog-error.png' />
+ </form>
+ </td>
+ </tr>
+ </table>
+END
+ &Header::closebox();
+ &Header::closebigbox();
+ &Header::closepage();
+ exit;
+
+} elsif (($cgiparams{'ACTION'} eq 'remove') && ($pagemode eq $PM_DEFAULT)) {
+ &Header::openbox("100%", "center", $Lang::tr{'request'});
+
+ my @pkgs = split(/\|/, $cgiparams{'DELPAKS'});
+ my @output = &General::system_output("/usr/local/bin/pakfire", "resolvedeps", "--no-colors", @pkgs);
+ print <<END;
+ <table style="width: 100%"><tr><td colspan='2'><p>$Lang::tr{'pakfire uninstall package'} <strong>@{pkgs}</strong><br>
+ $Lang::tr{'pakfire possible dependency'}</p>
+ <pre>
+END
+ foreach (@output) {
+ $_ =~ s/\\e\[[0-1]\;[0-9]+m//g;
+ print "$_\n";
+ }
+ print <<END;
+ </pre></td></tr>
+ <tr><td colspan='2'>$Lang::tr{'pakfire uninstall all'}</td></tr>
+ <tr><td colspan='2'> </td></tr>
+ <tr><td align='right'><form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <input type='hidden' name='DELPAKS' value='$cgiparams{'DELPAKS'}' />
+ <input type='hidden' name='FORCE' value='on' />
+ <input type='hidden' name='ACTION' value='remove' />
+ <input type='image' alt='$Lang::tr{'uninstall'}' title='$Lang::tr{'uninstall'}' src='/images/go-next.png' />
+ </form>
+ </td>
+ <td align='left'>
+ <form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <input type='hidden' name='ACTION' value='' />
+ <input type='image' alt='$Lang::tr{'abort'}' title='$Lang::tr{'abort'}' src='/images/dialog-error.png' />
+ </form>
+ </td>
+ </tr>
+ </table>
END
&Header::closebox();
&Header::closebigbox();
&Header::closepage();
exit;
- refreshpage();
}
-my $core_release = `cat /opt/pakfire/db/core/mine 2>/dev/null`;
-chomp($core_release);
-my $core_update_age = &General::age("/opt/pakfire/db/core/mine");
-my $corelist_update_age = &General::age("/opt/pakfire/db/lists/core-list.db");
-my $server_update_age = &General::age("/opt/pakfire/db/lists/server-list.db");
-my $packages_update_age = &General::age("/opt/pakfire/db/lists/packages_list.db");
+# Show Pakfire main page
+my %selected=();
+my %checked=();
+
+$selected{"TREE"} = ();
+$selected{"TREE"}{"stable"} = "";
+$selected{"TREE"}{"testing"} = "";
+$selected{"TREE"}{"unstable"} = "";
+$selected{"TREE"}{$pakfiresettings{"TREE"}} = "selected";
&Header::openbox("100%", "center", "Pakfire");
print <<END;
- <table width='95%' cellpadding='5' >
+ <table id="pfmain">
END
-if ( -e "/var/run/need_reboot") {
- print "<tr><td align='center' colspan='2'><font color='red'>$Lang::tr{'needreboot'}!</font></td></tr>";
- print "<tr><td colspan='2'> </font></td></tr>"
+if ("$pakfire_status{'RebootRequired'}" eq "yes") {
+ print "\t\t<tr><td colspan='2'><a href='/cgi-bin/shutdown.cgi'>$Lang::tr{'needreboot'}!</a></td></tr>\n";
}
+
print <<END;
- <tr><td width="50%" bgcolor='$color{'color20'}' align="center"><b>$Lang::tr{'pakfire system state'}:</b>
- <td width="50%">
- <tr><td align="center">$Lang::tr{'pakfire core update level'}: $core_release<hr />
- $Lang::tr{'pakfire last update'} $core_update_age $Lang::tr{'pakfire ago'}<br />
- $Lang::tr{'pakfire last serverlist update'} $server_update_age $Lang::tr{'pakfire ago'}<br />
- $Lang::tr{'pakfire last core list update'} $corelist_update_age $Lang::tr{'pakfire ago'}<br />
- $Lang::tr{'pakfire last package update'} $packages_update_age $Lang::tr{'pakfire ago'}
- <form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <input type='hidden' name='ACTION' value='update' />
- <input type='submit' value='$Lang::tr{'calamaris refresh list'}' /><br />
- </form>
- <td align="center">
- <form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <select name="UPDPAKS" size="5" disabled>
+ <tr><td class="heading">$Lang::tr{'pakfire system state'}:</td>
+ <td class="heading">$Lang::tr{'available updates'}:</td></tr>
+
+ <tr><td><strong>$Lang::tr{'pakfire core update level'}: $pakfire_status{'Release'}</strong>
+ <hr>
+ <div class="pflist">
+ $Lang::tr{'pakfire last update'} $pakfire_status{'LastUpdate'} $Lang::tr{'pakfire ago'}<br>
+ $Lang::tr{'pakfire last serverlist update'} $pakfire_status{'LastServerListUpdate'} $Lang::tr{'pakfire ago'}<br>
+ $Lang::tr{'pakfire last core list update'} $pakfire_status{'LastCoreListUpdate'} $Lang::tr{'pakfire ago'}<br>
+ $Lang::tr{'pakfire last package update'} $pakfire_status{'LastPakListUpdate'} $Lang::tr{'pakfire ago'}
+ </div>
+ <form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <input type='hidden' name='ACTION' value='update' />
+ <input type='submit' value='$Lang::tr{'calamaris refresh list'}' />
+ </form>
+ </td>
+ <td>
+ <form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <select name="UPDPAKS" class="pflist" size="5" disabled>
END
- &Pakfire::dblist("upgrade", "forweb");
+
+ if ("$pakfire_status{'CoreUpdateAvailable'}" eq "yes") {
+ print "<option value=\"core\">$Lang::tr{'core update'} -- $pakfire_status{'CoreVersion'} -- $Lang::tr{'release'}: $pakfire_status{'Release'} -> $pakfire_status{'AvailableRelease'}</option>\n";
+ }
+
+ if ($pakfire_status{'PakUpdatesAvailable'} > 0) {
+ my %upgradelist = &Pakfire::dblist("upgrade");
+ foreach my $pak (sort keys %upgradelist) {
+ print "<option value=\"$pak\">$Lang::tr{'pak update'}: $pak -- $Lang::tr{'version'}: $upgradelist{$pak}{'ProgVersion'} -> $upgradelist{$pak}{'AvailableProgVersion'} -- $Lang::tr{'release'}: $upgradelist{$pak}{'Release'} -> $upgradelist{$pak}{'AvailableRelease'}</option>\n";
+ }
+ }
+
print <<END;
</select>
- <br />
<input type='hidden' name='ACTION' value='upgrade' />
- <input type='image' alt='$Lang::tr{'upgrade'}' src='/images/document-save.png' />
+ <input type='image' alt='$Lang::tr{'upgrade'}' title='$Lang::tr{'upgrade'}' src='/images/document-save.png' />
</form>
-
- <tr><td colspan="2"><!-- Just an empty line -->
- <tr><td bgcolor='$color{'color20'}' align="center"><b>$Lang::tr{'pakfire available addons'}</b>
- <td bgcolor='$color{'color20'}' align="center"><b>$Lang::tr{'pakfire installed addons'}</b>
- <tr><td align="center">
- <p>$Lang::tr{'pakfire install description'}</p>
- <form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <select name="INSPAKS" size="10" multiple>
+ </td>
+ </tr>
+ <tr><td class="heading">$Lang::tr{'pakfire available addons'}</td>
+ <td class="heading">$Lang::tr{'pakfire installed addons'}</td></tr>
+
+ <tr><td style="padding:5px 10px 20px 20px" align="center"><p>$Lang::tr{'pakfire install description'}</p>
+ <form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <select name="INSPAKS" class="pflist" size="10" multiple>
END
- &Pakfire::dblist("notinstalled", "forweb");
-print <<END;
- </select>
- <br />
- <input type='hidden' name='ACTION' value='install' />
- <input type='image' alt='$Lang::tr{'install'}' src='/images/list-add.png' />
- </form>
-
- <td align="center">
- <p>$Lang::tr{'pakfire uninstall description'}</p>
- <form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <select name="DELPAKS" size="10" multiple>
+ my %notinstalledlist = &Pakfire::dblist("notinstalled");
+ foreach my $pak (sort keys %notinstalledlist) {
+ print "<option value=\"$pak\">$pak-$notinstalledlist{$pak}{'ProgVersion'}-$notinstalledlist{$pak}{'Release'}</option>\n";
+ }
+
+ print <<END;
+ </select>
+ <input type='hidden' name='ACTION' value='install' />
+ <input type='image' alt='$Lang::tr{'install'}' title='$Lang::tr{'install'}' src='/images/list-add.png' />
+ </form>
+ </td>
+ <td style="padding:5px 10px 20px 20px" align="center"><p>$Lang::tr{'pakfire uninstall description'}</p>
+ <form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <select name="DELPAKS" class="pflist" size="10" multiple>
END
- &Pakfire::dblist("installed", "forweb");
+ my %installedlist = &Pakfire::dblist("installed");
+ foreach my $pak (sort keys %installedlist) {
+ print "<option value=\"$pak\">$pak-$installedlist{$pak}{'ProgVersion'}-$installedlist{$pak}{'Release'}</option>\n";
+ }
-print <<END;
- </select>
- <br />
- <input type='hidden' name='ACTION' value='remove' />
- <input type='image' alt='$Lang::tr{'remove'}' src='/images/list-remove.png' />
- </form>
+ print <<END;
+ </select>
+ <input type='hidden' name='ACTION' value='remove' />
+ <input type='image' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' src='/images/list-remove.png' />
+ </form>
+ </td>
+ </tr>
</table>
END
&Header::openbox("100%", "center", "$Lang::tr{'settings'}");
print <<END;
- <form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <form method='POST' action='$ENV{'SCRIPT_NAME'}'>
<table width='95%'>
- <tr><td colspan='2' bgcolor='$color{'color20'}'><b>$Lang::tr{'basic options'}</b></td></tr>
- <tr><td align='left' width='45%'>$Lang::tr{'pakfire update daily'}</td><td width="55%" align="left">
- on <input type='radio' name='AUTOUPDATE' value='on' $checked{'AUTOUPDATE'}{'on'} /> |
- <input type='radio' name='AUTOUPDATE' value='off' $checked{'AUTOUPDATE'}{'off'} /> off </td></tr>
- <tr><td align='left' width='45%'>$Lang::tr{'pakfire health check'}</td><td align="left">
- on <input type='radio' name='HEALTHCHECK' value='on' $checked{'HEALTHCHECK'}{'on'} /> |
- <input type='radio' name='HEALTHCHECK' value='off' $checked{'HEALTHCHECK'}{'off'} /> off </td></tr>
- <tr><td align='left' width='45%'>$Lang::tr{'pakfire register'}</td><td align="left">
- on <input type='radio' name='UUID' value='on' $checked{'UUID'}{'on'} /> |
- <input type='radio' name='UUID' value='off' $checked{'UUID'}{'off'} /> off </td></tr>
- <tr><td colspan="2" align="center"><input type="submit" name="ACTION" value="$Lang::tr{'save'}" /></td></tr>
+ <tr>
+ <td align='left' width='45%'>$Lang::tr{'pakfire tree'}</td>
+ <td width="55%" align="left">
+ <select name="TREE">
+ <option value="stable" $selected{"TREE"}{"stable"}>$Lang::tr{'pakfire tree stable'}</option>
+ <option value="testing" $selected{"TREE"}{"testing"}>$Lang::tr{'pakfire tree testing'}</option>
+ <option value="unstable" $selected{"TREE"}{"unstable"}>$Lang::tr{'pakfire tree unstable'}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2"> </td>
+ </tr>
+ <tr>
+ <td colspan="2" align="center">
+ <input type="submit" name="ACTION" value="$Lang::tr{'save'}" />
+ </td>
+ </tr>
</table>
</form>
END
&Header::closebox();
&Header::closebigbox();
&Header::closepage();
+
+###--- Internal functions ---###
+
+# Check if pakfire is already running (extend test here if necessary)
+sub _is_pakfire_busy {
+ # Return immediately if lockfile is present
+ if(-e "$Pakfire::lockfile") {
+ return 1;
+ }
+
+ # Check if a PID of a running pakfire instance is found
+ # (The system backpipe command is safe, because no user input is computed.)
+ my $pakfire_pid = `pidof -s /usr/local/bin/pakfire`;
+ chomp($pakfire_pid);
+
+ if($pakfire_pid) {
+ return 1;
+ }
+
+ # Pakfire isn't running
+ return 0;
+}
+
+# Send HTTP headers
+sub _start_json_output {
+ print "Cache-Control: no-cache, no-store\n";
+ print "Content-Type: application/json\n";
+ print "\n"; # End of HTTP headers
+}
+
+# Send HTTP 303 redirect headers to change page mode
+# GET is always used to display the redirected page, which will remove already processed POST form data.
+# Note: Custom headers must be sent before the HTML output is started by &Header::showhttpheaders().
+# If switch_mode is set to true, the global page mode variable ("$pagemode") is also updated immediately.
+sub _http_pagemode_redirect {
+ my ($mode, $switch_mode) = @_;
+ $mode //= $PM_DEFAULT;
+ $switch_mode //= 0;
+
+ # Send HTTP redirect with GET parameter
+ my $location = "https://$ENV{'SERVER_NAME'}:$ENV{'SERVER_PORT'}$ENV{'SCRIPT_NAME'}?mode=${mode}";
+ print "Status: 303 See Other\n";
+ print "Location: $location\n";
+
+ # Change global page mode
+ if($switch_mode) {
+ $pagemode = $mode;
+ }
+}