summaryrefslogblamecommitdiffstats
path: root/modules-available/serversetup-bwlp-ipxe/inc/ipxemenu.inc.php
blob: 3ffecba1ca2fb7d722d110dc219c638554960d6d (plain) (tree)
1
2
3
4
5
6
7
8
9




              


                                            
                          


                                                                                
                          


                                                  
                      


                                         
                               


                           
                           
 
                                                                                       














                                                                                                                   
                                                
         

                                                           
                                                      
                                                          

                                                                                                              



                                                                                             
                                        

                                                             
                                                                            

                                                                         
                 
                                                             

         
                                       



                                    
                                        






                                                   
                                        




                                           

                                                               
                                                  

                                                 
                                                                           




                                             















                                                                                           
                                                    




























                                                                                            



           
                                                                     

                              
                                                       


                                                                             




                                                                                                            


                                                                                                         
                                                        





















                                                                                                                                        
                                                                             

                                
                                                       

                                                                             
                                                       




                                                                                                      
                             






                                    

                                     





                                                     







                                                                               
 
<?php

class IPxeMenu
{

	/**
	 * @var int ID of this menu, from DB
	 */
	protected $menuid;
	/**
	 * @var int 0 = disabled, otherwise, launch default option after timeout
	 */
	public $timeoutMs;
	/**
	 * @var string title to display above menu
	 */
	public $title;
	/**
	 * @var int menu entry id from DB
	 */
	public $defaultEntryId;
	/**
	 * @var MenuEntry[]
	 */
	public $items = [];

	public static function get(int $menuId, bool $emptyFallback = false): ?IPxeMenu
	{
		$menu = Database::queryFirst("SELECT menuid, timeoutms, title, defaultentryid FROM serversetup_menu
			WHERE menuid = :menuid LIMIT 1", ['menuid' => $menuId]);
		if ($menu !== false)
			return new IPxeMenu($menu);
		if (!$emptyFallback)
			return null;
		return new EmptyIPxeMenu();
	}

	/**
	 * IPxeMenu constructor.
	 *
	 * @param array $menu array for according menu row
	 */
	public function __construct(array $menu)
	{
		$this->menuid = (int)$menu['menuid'];
		$this->timeoutMs = (int)$menu['timeoutms'];
		$this->title = (string)$menu['title'];
		$defaultEntryId = $menu['defaultentryid'];
		$res = Database::simpleQuery("SELECT e.menuentryid, e.entryid, e.refmenuid, e.hotkey, e.title,
       	e.hidden, e.sortval, e.md5pass, b.module, b.data AS bootentry, b.title AS betitle
			FROM serversetup_menuentry e
			LEFT JOIN serversetup_bootentry b USING (entryid)
			WHERE e.menuid = :menuid
			ORDER BY e.sortval ASC, e.title ASC", ['menuid' => $menu['menuid']]);
		foreach ($res as $row) {
			$this->items[] = new MenuEntry($row);
		}
		// Make sure we have a default entry if the menu isn't empty
		if ($defaultEntryId === null && !empty($this->items)) {
			$defaultEntryId = $this->items[0]->menuEntryId();
		}
		$this->defaultEntryId = (int)$defaultEntryId;
	}

	public function title(): string
	{
		return $this->title;
	}

	public function timeoutMs(): int
	{
		return $this->timeoutMs;
	}

	/**
	 * @return int Number of items in this menu
	 */
	public function itemCount(): int
	{
		return count($this->items);
	}

	/**
	 * @return MenuEntry|null Return preselected menu entry
	 */
	public function defaultEntry(): ?MenuEntry
	{
		foreach ($this->items as $item) {
			if ($item->menuEntryId() === $this->defaultEntryId)
				return $item;
		}
		return null;
	}

	private function maybeOverrideDefault(string $uuid)
	{
		$e = $this->defaultEntry();
		// Shortcut - is already bwlp and timeout is reasonable (1-15s), do nothing
		$defIsMl = $e !== null && substr($e->internalId(), 0, 3) === 'ml-';
		$timeoutOk = $this->timeoutMs > 0 && $this->timeoutMs <= 15000;
		if ($timeoutOk && $defIsMl)
			return;
		// No runmode module anyways
		if (!Module::isAvailable('runmode'))
			return;
		$rm = RunMode::getRunMode($uuid);
		// No runmode for this client, cannot be PVSmgr
		if ($rm === false)
			return;
		// Is not pvsmgr
		if ($rm['module'] !== 'roomplanner')
			return;
		// See if it's a dedicated station, if so make sure it boots into bwLehrpool
		$data = json_decode($rm['modedata'], true);
		if ($data['dedicatedmgr'] ?? false) {
			if (!$defIsMl) {
				$this->overrideDefaultToMinilinux();
			}
			if (!$timeoutOk) {
				$this->timeoutMs = 5000;
			}
		}
	}

	/**
	 * Patch the menu to make sure bwLehrpool/"MiniLinux" is the default
	 * boot option, and set timeout to something reasonable. This is used
	 * for dedicated PVS managers, as they might not have a keyboard
	 * connected.
	 */
	private function overrideDefaultToMinilinux()
	{
		foreach ($this->items as $item) {
			if (substr($item->internalId(), 0, 3) === 'ml-') {
				$this->defaultEntryId = $item->menuEntryId();
				return;
			}
		}
	}

	/*
	 *
	 */

	public static function forLocation(int $locationId): IPxeMenu
	{
		$chain = null;
		if (Module::isAvailable('locations')) {
			$chain = Location::getLocationRootChain($locationId);
		}
		if (!empty($chain)) {
			$res = Database::simpleQuery("SELECT m.menuid, m.timeoutms, m.title,
       				IFNULL(ml.defaultentryid, m.defaultentryid) AS defaultentryid, ml.locationid
					FROM serversetup_menu m
					INNER JOIN serversetup_menu_location ml USING (menuid)
					WHERE ml.locationid IN (:chain)", ['chain' => $chain]);
			if ($res->rowCount() > 0) {
				// Make the location id key, preserving order (closest location is first)
				$chain = array_flip($chain);
				foreach ($res as $row) {
					// Overwrite the value (numeric ascending values, useless) with menu array of according location
					$chain[(int)$row['locationid']] = $row;
				}
				// Use first one that was found
				foreach ($chain as $menu) {
					if (is_array($menu)) {
						return new IPxeMenu($menu);
					}
				}
				// Should never end up here, but we'd just fall through and use the default
			}
		}
		// We're here, no specific menu, use default
		$menu = Database::queryFirst("SELECT menuid, timeoutms, title, defaultentryid
			FROM serversetup_menu
			ORDER BY isdefault DESC LIMIT 1");
		if ($menu === false) {
			return new EmptyIPxeMenu;
		}
		return new IPxeMenu($menu);
	}

	public static function forClient(string $ip, ?string $uuid): IPxeMenu
	{
		$locationId = 0;
		if (Module::isAvailable('locations')) {
			$locationId = Location::getFromIpAndUuid($ip, $uuid);
		}
		$menu = self::forLocation($locationId);
		if ($uuid !== null) {
			// Super specialcase hackery: If this is a dedicated PVS, force the default to
			// be bwlp/"minilinux"
			$menu->maybeOverrideDefault($uuid);
		}
		return $menu;
	}

}

class EmptyIPxeMenu extends IPxeMenu
{

	public function __construct()
	{
		parent::__construct([
			'menuid' => -1,
			'timeoutms' => 120,
			'defaultentryid' => null,
			'title' => 'No menu defined',
		]);
		$this->items[] = new MenuEntry([
			'title' => 'Please create a menu in Server-Setup first'
		]);
		$this->items[] = new MenuEntry([
			'title' => 'Bitte erstellen Sie zunächst ein Menü'
		]);
	}

}