Some backend changes to webserver to allow IPv6 binding
<?php/** * Utility functions * * Greyhound - real web management for Amarok * Copyright (C) 2008 Dan Fuhry * * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. *//** * Utility/reporting functions *//** * Report a fatal error and exit * @param string Error message */function burnout($msg){ global $use_colors; $h = @fopen('php://stderr', 'w'); if ( $use_colors ) { fwrite($h, "\x1B[31;1m[Greyhound] fatal: \x1B[37;1m"); fwrite($h, "$msg\x1B[0m\n"); } else { fwrite($h, "[Greyhound] fatal: $msg\n"); } fclose($h); exit(1);}/** * Print a stylized status message, compatible with Linux consoles. Falls back to no control characters if on unsupported terminal. * @param string Status message */function status($msg){ global $use_colors; $h = @fopen('php://stderr', 'w'); $label = ( defined('HTTPD_WS_CHILD') ) ? 'Child ' . substr(strval(getmypid()), -3) : 'Greyhound'; if ( $use_colors ) { fwrite($h, "\x1B[32;1m[$label] \x1B[32;0m$msg\x1B[0m\n"); } else { fwrite($h, "[$label] $msg\n"); } fclose($h);}/** * Print a stylized warning message, compatible with Linux consoles * @param string message message */function warning($msg){ global $use_colors; $h = @fopen('php://stderr', 'w'); if ( $use_colors ) { fwrite($h, "\x1B[33;1m[Greyhound] \x1B[0m\x1B[33mWarning:\x1B[0m $msg\n"); } else { fwrite($h, "[Greyhound] Warning: $msg\n"); } fclose($h);}/** * Performs an action with DCOP. * @param string DCOP component, e.g. player, playlist, playlistbrowser, ... * @param string Action to perform, e.g. stop, play, ... * @param string additional parameters... (NOT IMPLEMENTED) * @return mixed output of DCOP command */function dcop_action($component, $action){ $tmpfile = tempnam('amaweb', ''); if ( !$tmpfile ) burnout('tempnam() failed us'); system("dcop amarok $component $action > $tmpfile"); $output = @file_get_contents($tmpfile); @unlink($tmpfile); $output = trim($output); // detect type of output if ( $output == 'true' ) return true; else if ( $output == 'false' ) return false; else if ( preg_match('/^-?[0-9]+/', $output) ) return intval($output); else return $output;}/** * Rebuilds the copy of the playlist in RAM */$playlist_last_md5 = '';function rebuild_playlist(){ // import what we need global $playlist, $amarok_home; // sync and load the playlist file $playlist_file = dcop_action('playlist', 'saveCurrentPlaylist'); // do we have amarok's home? if ( !$amarok_home ) $amarok_home = dirname($playlist_file); // check MD5 - if it's not changed, exit to save CPU cycles global $playlist_last_md5; $effective_md5 = md5_playlist_file($playlist_file); if ( $playlist_last_md5 == $effective_md5 ) { return true; } status('Rebuilding playlist cache'); $playlist_last_md5 = $effective_md5; // start XML parser try { $xml = simplexml_load_file($playlist_file); } catch ( Exception $e ) { burnout("Caught exception trying to load playlist file:\n$e"); } $attribs = $xml->attributes(); if ( @$attribs['product'] != 'Amarok' ) { burnout('Playlist is not in Amarok format'); } $playlist = array(); foreach ( $xml->children() as $child ) { $attribs = $child->attributes(); $item = array( 'uri' => $attribs['uri'], 'title' => strval($child->Title), 'artist' => strval($child->Artist), 'album' => strval($child->Album), 'length' => seconds_to_str(intval($child->Length)), 'length_int' => intval($child->Length) ); $playlist[] = $item; } // if we're a child process, signal the parent to update if ( defined('HTTPD_WS_CHILD') ) { global $httpd; posix_kill($httpd->parent_pid, SIGUSR1); }}/** * Builds the correct MD5 check for the specified playlist XML file. This is designed to base on the list of actual tracks, disregarding * the rest of the text in the XML file. * @param string Path to playlist * @return string hash */function md5_playlist_file($file){ $contents = @file_get_contents($file); if ( empty($contents) ) return false; $count = preg_match_all('/uniqueid="([a-fA-F0-9]+?)"/', $contents, $matches); $matches = implode("", $matches[1]); if ( empty($matches) ) { // sometimes current.xml has blank unique IDs $count = preg_match_all('/url="([^"]+?)"/', $contents, $matches); $matches = implode("", $matches[1]); } return md5($matches);}/** * Converts a number to minute:second format * @param int Seconds * @return string format: mm:ss */function seconds_to_str($secs){ $seconds = $secs % 60; $minutes = ( $secs - $seconds ) / 60; $seconds = strval($seconds); $minutes = strval($minutes); if ( strlen($seconds) < 2 ) $seconds = "0$seconds"; if ( strlen($minutes) < 2 ) $minutes = "0$minutes"; return "$minutes:$seconds";}/** * Loads the specified theme into Smarty * @param string Theme ID * @return object Smarty object */function load_theme($theme_id){ global $httpd; static $smarty = array(); if ( $theme_id === '__free__' ) { $smarty = array(); return false; } if ( !isset($smarty[$theme_id]) ) { $smarty[$theme_id] = new Smarty(); $smarty[$theme_id]->template_dir = GREY_ROOT . "/themes/$theme_id"; if ( !is_dir("./compiled/$theme_id") ) @mkdir("./compiled/$theme_id"); $smarty[$theme_id]->compile_dir = "./compiled/$theme_id"; $smarty[$theme_id]->config_dir = "./config"; $httpd->add_handler("themes/$theme_id", 'dir', GREY_ROOT . "/themes/$theme_id"); } return $smarty[$theme_id];}/** * Implementation of the "which" command in native PHP. * @param string command * @return string path to executable, or false on failure */function which($executable){ $path = ( isset($_ENV['PATH']) ) ? $_ENV['PATH'] : ( isset($_SERVER['PATH']) ? $_SERVER['PATH'] : false ); if ( !$path ) // couldn't get OS's PATH return false; $win32 = ( PHP_OS == 'WINNT' || PHP_OS == 'WIN32' ); $extensions = $win32 ? array('.exe', '.com', '.bat') : array(''); $separator = $win32 ? ';' : ':'; $paths = explode($separator, $path); foreach ( $paths as $dir ) { foreach ( $extensions as $ext ) { $fullpath = "$dir/{$executable}{$ext}"; if ( file_exists($fullpath) && is_executable($fullpath) ) { return $fullpath; } } } return false;}/** * Reload the config. */function grey_reload_config(){ global $httpd; status('reloading the config'); if ( file_exists('./greyhound-config.php') ) { require('./greyhound-config.php'); } else { // ignore this, it allows using a different config file when a Mercurial repository // exists in Greyhound's root directory (to allow the devs to have their own config // separate from the default) if ( @is_dir(GREY_ROOT . '/.hg') ) require(GREY_ROOT . '/config.dev.php'); else require(GREY_ROOT . '/config.php'); } foreach ( array('public', 'enable_ipv4', 'enable_ipv6', 'allowcontrol', 'theme', 'allow_fork', 'use_auth', 'auth_data', 'configpass') as $var ) { if ( isset($$var) ) { $GLOBALS[$var] = $$var; } }}