<?php
/*
 * $Revision: 1.9 $
 * $Date: 2012/03/01 21:38:57 $
 * modify by killerman and kmarty for dsapacTV
 * Autori se zrikaji jakekoliv odpovednosti za pripadne skody zpusobene pouzivanim tohoto scriptu
 *
 */

define("I_NAME", "Updater for dsapacTV v");
define("I_VERSION", "3.4");
define("I_AUTOR", "kmarty wencaS killerman");

# Config part - BEGIN
define("PKGS_URL", 'http://dsapactv.wencas.cz/packages.php');
# Config part - END

# INFO:
# install.php (a jeho soubory) je umisten v .../scripts/<nazev_projektu>/install/
# Balicky budou rozbaleny do .../scripts/ (balicky musi obsahovat <nazev_projektu> jako pocatecni adresar), takto:
# Archive contains:
#  xLiveCZ/
#  xLiveCZ/rtmpdump.sh
#  postinst.sh
#
# Soubor 'postinst.sh' v balicku musi volat cesty relativne a s vedomim ze je spousten z adresare ../scripts/
# Adresar 'Xtreamering' je ocekavan v .../scripts/
#

define('INSTALLPHP_URL', 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']);
define('INSTALLPHP_DIR', dirname(__FILE__).'/');
define('SCRIPTS_URL_DIR', current(explode('scripts/', INSTALLPHP_URL)).'scripts/');
define('XTREAMERING_URL', SCRIPTS_URL_DIR.'Xtreamering/index.php');

define('SCRIPTS_DIR',current(explode('scripts/', __FILE__)).'scripts/');
define('DWNLD_DIR', current(explode('scripts/', __FILE__)));
define('PKG_DIR', current(explode('install/',__FILE__)));

define('LOGFILE', INSTALLPHP_DIR.'dsapacupdate.log');


$item_nr = 0; //definuje "pocitadlo" pro funkci addItem()
###########

if (isset($_GET['action'])) {
	# Sesny na Xtreameru nefungujou, musim to resit takhle.
	load_ary('/tmp/packages.json_var',&$packages);
	load_ary('/tmp/pkgs_installed.json_var', &$pkgs_installed);
	load_ary('/tmp/pkgs_2b_updated.json_var', &$pkgs_2b_updated);
}

switch ($_GET['action']) {
	case 'install':		# TODO: Dat tomu nejaky lepsi nazev at se to minimalne historicky neplete s 'install_single'
		switch ($_GET['type']) {
			case 'update':
				$msg = "Update was successful";
				write2log("\n----------- PROCESS UPDATE -----------\n");
				if (! isset($pkgs_2b_updated)) {
					$msg = "ERROR: Missing\$pkgs_2b_updated";
				} else {
					$pkgs_list = $pkgs_2b_updated;
				}
				break;
			case 'reinstall':
				$msg = "Reinstall was successful";
				write2log("\n----------- PROCESS REINSTALATION -----------\n");
				if (! isset($pkgs_installed)) {
					$msg = "ERROR: Missing\$pkgs_installed";
				} else {
					$pkgs_list = array_keys($pkgs_installed);
				}
				break;
			case 'all':
				$msg = "All instalations are successful";
				write2log("\n----------- PROCESS INSTALL ALL -----------\n");
				if (! isset($packages)) {
					$msg = "ERROR: Missing\$packages";
				} else {
					$pkgs_list = array_keys($packages);
				}
				break;
			default:
				$msg = "Missing or unknown value in \$_GET['type'] = \"".(isset($_GET['type']) ? $_GET['type'] : "")."\"";
				break;
		}

		xmlHeader();

		if (isset($pkgs_list)) {
			foreach ($pkgs_list as $pkg) {
				if (! InstallPkg($pkg, $packages, &$errstr)) {
					$msg = "ERROR: ".$pkg." - ".$errstr;
					break;
				}
			}
		}

		write2log($msg."\n");

		addItem($item_nr++, 'Return to menu', $msg, logtail(LOGFILE), INSTALLPHP_URL);
		xmlFooter();

		break;

	case 'install_single':
		write2log("\n----------- PROCESS INSTALATION -----------\n");
		xmlHeader();
		if (! isset($_GET['pkg'])) {
			$msg = "ERROR: Missing\$_GET['pkg']";
		}
		elseif (! InstallPkg($_GET['pkg'], $packages, &$errstr)) {
			$msg = "ERROR: ".$errstr;
		} else {
			$msg = "Installation was successful";
		}
		write2log($msg."\n");

		addItem($item_nr++, 'Return to menu', $msg, logtail(LOGFILE), INSTALLPHP_URL);

		xmlFooter();
		break;

	default:
		$packages = $pkgs_installed = $pkgs_2b_updated = array();

		write2log("===============================\n");

		# Nacti seznam vsech dostupnych balicku
		if (! $packages = getPackages(PKGS_URL)) {
			write2log("ERROR: Cannot read ".PKGS_URL."\n");
			xmlHeader();
			addItem($item_nr++, 'Return to menu', 'Unable to retrieve basic XML '.PKGS_URL, logtail(LOGFILE), XTREAMERING_URL);
			xmlFooter();
			exit(1);
		}

		write2log("Available version (name : available - installed):\n");
		foreach (array_keys($packages) as $package) {
			# Zjisti detaily o dostupnych baliccich
			$packages[$package] = array_merge($packages[$package],getVersion($packages[$package]['versioninfo']));

			# dtto o jiz nainstalovanych
			$installed_ver = getVersion(PKG_DIR.basename($packages[$package]['versioninfo']));
			if ($installed_ver['version'] != -1) {	# '-1' = balicek neni nainstalovan
				$pkgs_installed[$package] = $installed_ver['version'];

				# pokud ma dostupnou vyssi verzi nez nainstalovany, pridej ho do seznam k aktualizaci.
				if ($packages[$package]['version'] > $pkgs_installed[$package]) {
					$pkgs_2b_updated[] = $package;
				}
			}
			write2log($package." : ".$packages[$package]['version'].
					   " - ".(($installed_ver['version'] > 0) ? $installed_ver['version'] : "not installed")."\n");
		}

		# Potrebuju si tohle udrzet i pro install/reinstall/update a nechci to stahovat znovu.
		save_ary(&$packages, '/tmp/packages.json_var');
		save_ary(&$pkgs_installed, '/tmp/pkgs_installed.json_var');
		save_ary(&$pkgs_2b_updated, '/tmp/pkgs_2b_updated.json_var');

		# Vykresleni RSS - BEGIN
		xmlHeader();

 		if (count($pkgs_installed)) {
 			if (count($pkgs_2b_updated) > 1) {
 				# Tohle ma vyznam jen kdyz je aktualizaci vic nez jedna, jinak je to zbytecna polozka navic
 				addItem($item_nr++, "Update all (".sklonovani(count($pkgs_2b_updated), "update", "update", "updates").")",
 					'Install all available updates',
 					'Packed update: '.implode(", ", $pkgs_2b_updated),
 					INSTALLPHP_URL."?action=install&amp;type=update");
 			}
 		} else {
 			# Neni-li nic nainstalovane, nabidni instalaci vsech dostupnych balicku (typicky prvotni instalace)
 			addItem($item_nr++, "Install all (".sklonovani(count($packages), "package", "packages", "packages").")",
 				'Install all available packages',
 				'Packages to install: '.implode(", ", array_keys($packages)),
 				INSTALLPHP_URL."?action=install&amp;type=all");
 		}

		# Vypis seznam aktualizovatelnych balicku
		foreach ($pkgs_2b_updated as $package) {
			addItem($item_nr++, "Update ".$package." v".$packages[$package]['version'],
				$packages[$package]['description'], $packages[$package]['popupinfo'],
				INSTALLPHP_URL."?action=install_single&amp;pkg=".urlencode($package));
		}

		# Zakladni navrat do menu Xtreameringu
		addItem($item_nr++, ((count($pkgs_2b_updated) || (count($pkgs_installed) < count($packages))) ? 'Do not install now' : 'Nothing to update')
			.', Return to menu',
			'Return to Xtreamering menu. Not working on Xtreamer Prodigy. For Xtreamer Prodigy users - press button return.', logtail(LOGFILE), XTREAMERING_URL);

		# Pokud jsou nejake balicky nainstalovany a zaroven neni nic k aktualizaci, nabidni moznost preinstalovat jiz nainstalovane balicky
		if (count($pkgs_installed) && (! count($pkgs_2b_updated))) {
			addItem($item_nr++, "Reinstall",
				'Reinstall',
				'For reinstall: '.implode(", ",array_keys($pkgs_installed)),
				INSTALLPHP_URL."?action=install&amp;type=reinstall");
		}

		# Vypis seznam nenainstalovanych balicku
		foreach (array_keys($packages) as $package) {
			if (! isset($pkgs_installed[$package])) {
				addItem($item_nr++, "Download & Install ".$package." v".$packages[$package]['version'],
					$packages[$package]['description'], $packages[$package]['popupinfo'],
					INSTALLPHP_URL."?action=install_single&amp;pkg=".urlencode($package));
			}
		}

		xmlFooter();
		# Vykresleni RSS - END
		break;
}


#############
# Functions #
#############
function save_ary($ar, $fajl) {
	return file_put_contents($fajl, json_encode($ar));
}

function load_ary($fajl, $ar) {
	if (file_exists($fajl)) {
		$ar = json_decode(file_get_contents($fajl),TRUE);
		@unlink($fajl);
		return true;
	}
	return false;
}

function getPackages($url) {
	if (! $xml = @simplexml_load_file($url)) {
		return false;
	}
	$a_xml = json_decode(json_encode($xml),TRUE);

	# klic 'package' prejmenovat podle ['package']['product']
	# + klic ['package']['product'] vyhodit
	if (isset($a_xml['package'][0])) {
		# Balicku je vic, pole ma pak mezivrstvu, kvuli duplicitam 'package'
		# Pryc s ni, duplicity resi unikatni jmeno balicku
		foreach(array_keys($a_xml['package']) as $pkg) {
			$a_out[$a_xml['package'][$pkg]['product']] = $a_xml['package'][$pkg];
			unset($a_out[$a_xml['package'][$pkg]['product']]['product']);
		}
	} else {
		$a_out[$a_xml['package']['product']] = $a_xml['package'];
		unset($a_out[$a_xml['package']['product']]['product']);
	}
	return $a_out;
}

function getVersion($url) {
	if ((! preg_match('/^http/',$url)) && (! file_exists($url))) {
		# Jde o lokalni soubor a navic neexistuje
		# Nutno doplnit alespon verzi
		$a_xml['version'] = -1;
		return $a_xml;
	}

	if (! $xml = @simplexml_load_file($url)) {
		$a_xml['version'] = "ERR";
		$a_xml['description'] = "ERROR: Unable to retrieve XML ".$url;
		return $a_xml;
	}
	$a_xml = json_decode(json_encode($xml),TRUE);

	# Z nasledujicich tri radku by mohl zatim zustat jen ten posledni - @attributes (zatim) nepouzivam
	unset($a_xml['@attributes']['model']);
	if (! count($a_xml['@attributes'])) {
		unset($a_xml['@attributes']);	# Tenhle
	}

	return $a_xml;
}

function InstallPkg($balik, $packages, $errstr) {
	if (! isset($packages[$balik])) {
		$errstr = "Missing\$packages['".$balik."']";
		return false;
	}
	$pkg = $packages[$balik];

	write2log("Installing package '".$balik."': ");

	if (! EnoughSpace(DWNLD_DIR, $pkg['needsize'])) {
		$errstr =  "Is not enough disk space.";
		return false;
	}

	if (! DownloadFile($pkg['downloadurl'], DWNLD_DIR.$pkg['localpath'])) {
		$errstr = "Failed to download file ".$pkg['downloadurl'];
		return false;
	}

	/*if (md5_file(DWNLD_DIR.$pkg['localpath']) != $pkg['checksum']) {
		$errstr = "Checksum does not match";
		return false;
	}*/

	write2log("\nUnziping:\n");
	write2log(shell_exec("unzip -o '".DWNLD_DIR.$pkg['localpath']."' -d '".SCRIPTS_DIR."' 2>&1"));
	# TODO: Mozna nejak zjistit jestli unzip uspel
	unlink(DWNLD_DIR.$pkg['localpath']);

	# 'postinst.sh' slouzi k dodatecnemu doladeni instalace. Napriklad nastaveni prav u spustitelnych souboru
	if (file_exists(SCRIPTS_DIR."postinst.sh")) {
		write2log("Nalezen 'postinst.sh', spoustim:\n");
		chmod(SCRIPTS_DIR."postinst.sh", 0755);
		write2log(shell_exec("cd ".SCRIPTS_DIR." && ./postinst.sh 2>&1"));
		unlink(SCRIPTS_DIR."postinst.sh");
	}

	# XML infofajl diky kterymu instalak vi ze je balik nainstalovan (a ktera verze)
	if (! DownloadFile($pkg['versioninfo'], PKG_DIR.basename($pkg['versioninfo']))) {
		$errstr = "Could not download XML info.";
		return false;
	}

	write2log("Finish.\n");
	return true;
}

function EnoughSpace($dir, $required) {
	if (floor(disk_free_space($dir)/1024/1024) < $required) {
		return false;
	}
	return true;
}

function addItem($item_nr, $title, $desc, $popupinfo, $link, $media = "") {
	echo	"<item>
      <title><![CDATA[".$title."]]></title>
      <label><![CDATA[".$desc."]]></label>
      <popupinfo><![CDATA[".$popupinfo."]]></popupinfo>
      ".($link ? "<link>".$link."</link>" : "").($media ? "<media:thumbnail url=\"".$media."\" />" : "")."
      <itemid>$item_nr</itemid>
      <curnum>".($item_nr+1)."</curnum>
    </item>
";
}

function DownloadFile($src, $dst) {
	if (! $fh_src = @fopen($src, 'rb')) {
		return false;
	}
	if (! $fh_dst = fopen($dst, 'wb')) {
		fclose($fh_src);
		return false;
	}
	while (! feof($fh_src)) {
		$buffer = fread($fh_src, 8192);
		fwrite($fh_dst, $buffer);
	}
	fclose($fh_dst);
	fclose($fh_src);
	return true;
}

function sklonovani($num, $text_1, $text_2_4, $text_5) {
    return "$num " . (abs($num) == 1 ? $text_1 : ($num == 0 || abs($num) >= 5 ? $text_5 : $text_2_4));
}

function write2log($msg) {
	if (! $fh = @fopen(LOGFILE, 'a')) {
		return false;
	}
	fwrite($fh, $msg);
	fclose($fh);
}

function logtail($logfajl) {
	# Drobet prasatkove (neni to ciste v PHP), nicmene nejkratsi mozne
	return shell_exec('tail -n 13 '.$logfajl);
}

function url_exists($url) {
	$hdrs = @get_headers($url);
	return is_array($hdrs) ? (preg_match('/^HTTP\\/\\d+\\.\\d+\\s+2\\d\\d\\s+.*$/',$hdrs[0]) ? true : false) : false;
}

function xmlHeader() {
	$header = '<?xml version="1.0" encoding="utf-8" ?>
<!-- VERZE '.I_VERSION.' '.I_NAME.' by '.I_AUTOR.' -->
<rss version="2.0" xmlns:media="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <script>
    PopUpImage="";
    PopUpMsg="";
  </script>
  <mediaDisplay name="threePartsView"
		sideLeftWidthPC="0" sideRightWidthPC="0"
		headerImageWidthPC="0"
		selectMenuOnRight="no"
		autoSelectMenu="no"
		autoSelectItem="no"
		itemImageHeightPC="0" itemImageWidthPC="0"
		itemXPC="10" itemYPC="20"
		itemWidthPC="45" itemHeightPC="8"
		capXPC="10" capYPC="20"
		capWidthPC="45" capHeightPC="64"
		itemBackgroundColor="0:0:0"
		itemPerPage="8"
		itemGap="0"
		bottomYPC="90"
		backgroundColor="0:0:0"
		showHeader="no"
		showDefaultInfo="no"
		imageFocus=""
		sliding="no"
		idleImageXPC="45" idleImageYPC="45"
		idleImageWidthPC="8" idleImageHeightPC="10">
';

	foreach (range(0,9) as $i)
		$header .= "    <idleImage>".INSTALLPHP_DIR."images/busy".$i.".png</idleImage>\n";

	$header .= '    <image redraw="no" offsetXPC="0" offsetYPC="0" widthPC="100" heightPC="18">
      <script>
        print("'.INSTALLPHP_DIR.'images/top.png");
      </script>
    </image>
    <image redraw="no" offsetXPC="4" offsetYPC="4" widthPC="11" heightPC="11">
      <script>
        print("'.INSTALLPHP_DIR.'images/logo.png");
      </script>
    </image>
    <text align="center" offsetXPC="0" offsetYPC="-2" widthPC="100" heightPC="20" fontSize="20" backgroundColor=-1:-1:-1 foregroundColor=250:250:250>'.
		I_NAME.' '.I_VERSION.'</text>
    <!--text align="left" offsetXPC="87" offsetYPC="3" widthPC="10" heightPC="11" fontSize="16" lines="3" backgroundColor=-1:-1:-1 foregroundColor=0:0:0>'.
		I_AUTOR.'</text-->
    <text redraw="yes"
          backgroundColor="0:0:0" foregroundColor="255:255:255"
          offsetXPC="88" offsetYPC="85" widthPC="10" heightPC="5" fontSize="16" lines="1">
      <script>
        getItemInfo("curnum") + " / " + getPageInfo("itemCount");
      </script>
    </text>
    <text redraw="yes"
	  backgroundColor="0:0:0" foregroundColor="255:255:255"
	  offsetXPC="55" offsetYPC="20" widthPC="40" heightPC="40" fontSize="16" lines="10">
      <script>
        getItemInfo("label");
      </script>
    </text>

    <!-- POPUP INFO START -->
    <text redraw="yes" offsetXPC="21.7" offsetYPC="15.7" widthPC="56.6" heightPC="61.6">
      <backgroundColor><script>bgColorB;</script></backgroundColor>
    </text>
    <text redraw="yes" offsetXPC="22" offsetYPC="16" widthPC="56" heightPC="61">
      <backgroundColor><script>bgColorA;</script></backgroundColor>
    </text>
    <text redraw="yes" alignt="center" tailDots="yes"
          backgroundColor="-1:-1:-1" foregroundColor="255:255:255"
          offsetXPC="25" offsetYPC="19" widthPC="50" heightPC="55" fontSize="14" lines="15">
      <script>
        print(PopUpMsg);
      </script>
    </text>
    <!-- POPUP INFO END -->

    <itemDisplay>
      <image redraw="no" offsetXPC="1" offsetYPC="1" widthPC="100" heightPC="100" >
        <script>
          getItemInfo(-1,"image");
        </script>
      </image>
      <image redraw="yes" offsetXPC="0" offsetYPC="0" widthPC="100" heightPC="100" >
        <script>
          if( getFocusItemIndex() == getItemInfo(-1,"itemid") )
            "'.INSTALLPHP_DIR.'images/focus.png";
          else
            "'.INSTALLPHP_DIR.'images/unfocus.png";
        </script>
      </image>
      <text align="center" redraw="yes" backgroundColor="-1:-1:-1"
            offsetXPC="8" offsetYPC="10" widthPC="80" heightPC="80" fontSize="16" lines="1">
        <script>
          getItemInfo(-1,"title");
        </script>
        <foregroundColor>
          <script>
            if( getFocusItemIndex() == getItemInfo(-1,"itemid") )
              "255:255:255";
            else
              "45:45:45";
          </script>
        </foregroundColor>
      </text>
    </itemDisplay>

    <onUserInput>
      <script>
        ret = "false";
        userInput = currentUserInput();
        if ( userInput == "DISPLAY" || userInput == "display" ) {
          executeScript("PopUpDetails");
          redrawDisplay();
          ret = "true";
        }
        ret;
      </script>
    </onUserInput>
  </mediaDisplay>

  <onExit>
    <script>
      setRefreshTime(-1);
      redrawDisplay();
    </script>
  </onExit>
  <onRefresh>
    <script>
      setRefreshTime(-1);
      redrawDisplay();
    </script>
  </onRefresh>

  <PopUpDetails>
    if ( PopUpMsg != "" ) {
      PopUpMsg = "";
      bgColorA = -1:-1:-1;
      bgColorB = -1:-1:-1;
    } else {
      bgColorA = "0:0:0";
      bgColorB = "164:0:49";

      curentindex = getFocusItemIndex();
      PopUpMsg = getItemInfo(curentindex,"popupinfo");
    }

    setRefreshTime(-1);
    redrawDisplay();
  </PopUpDetails>

  <channel>
    <title><![CDATA['.I_NAME.']]></title>
';

	echo $header;
}

function xmlFooter() {
	echo "  </channel>\n</rss>\n";
}

?>
