# HG changeset patch # User Dan # Date 1222226778 14400 # Node ID 1b4288399b1fc4ab0512aed67e9743e6c0436fa3 # Parent d62212462f9bbb10d5e59a9355fb5686dc5c3945 Added graphical configuration, at this point only for the grey theme but others will follow soon. (This has been nearly done for two weeks or more but was on hold due to the bugs with multithreading) diff -r d62212462f9b -r 1b4288399b1f functions.php --- a/functions.php Tue Sep 23 23:26:15 2008 -0400 +++ b/functions.php Tue Sep 23 23:26:18 2008 -0400 @@ -221,6 +221,11 @@ { global $httpd; static $smarty = array(); + if ( $theme_id === '__free__' ) + { + $smarty = array(); + return false; + } if ( !isset($smarty[$theme_id]) ) { $smarty[$theme_id] = new Smarty(); @@ -233,3 +238,61 @@ } 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'); + } +} + diff -r d62212462f9b -r 1b4288399b1f scripts/config.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/config.js Tue Sep 23 23:26:18 2008 -0400 @@ -0,0 +1,157 @@ +var userlist = []; + +function register_user(username) +{ + userlist.push(username); +} + +function draw_user(ul, username) +{ + var inp = document.createElement('input'); + inp.type = 'hidden'; + inp.name = 'users[]'; + inp.value = username; + ul.parentNode.appendChild(inp); + var li = document.createElement('li'); + li.username = username; + li.userinput = inp; + var delbtn = document.createElement('a'); + delbtn.style.color = '#ff0000'; + delbtn.href = '#'; + delbtn.onclick = function() + { + delete_user(this); + return false; + } + delbtn.appendChild(document.createTextNode('[X]')); + li.appendChild(delbtn); + + li.appendChild(document.createTextNode(' ' + username)); + ul.appendChild(li); +} + +function draw_new_user(username, password) +{ + for ( var i = 0; i < userlist.length; i++ ) + { + if ( userlist[i] == username ) + { + alert('The username you entered is already in the list, please delete the current user and re-add it if you want to change the password.'); + return false; + } + } + + userlist.push(username); + + var ul = document.getElementById('userlist'); + + var inp = document.createElement('input'); + inp.type = 'hidden'; + inp.name = 'users_add[' + username + ']'; + inp.value = password; + ul.parentNode.appendChild(inp); + var li = document.createElement('li'); + li.username = username; + li.userinput = inp; + var delbtn = document.createElement('a'); + delbtn.style.color = '#ff0000'; + delbtn.href = '#'; + delbtn.onclick = function() + { + delete_user(this); + return false; + } + delbtn.appendChild(document.createTextNode('[X]')); + li.appendChild(delbtn); + + li.appendChild(document.createTextNode(' ' + username)); + ul.appendChild(li); + + return true; +} + +function userlist_init() +{ + var ul = document.getElementById('userlist'); + for ( var i = 0; i < userlist.length; i++ ) + { + draw_user(ul, userlist[i]); + } +} + +function delete_user(a) +{ + var li = a.parentNode; + var username = li.username; + li.parentNode.parentNode.removeChild(li.userinput); + li.parentNode.removeChild(li); + + for ( var i = 0; i < userlist.length; i++ ) + { + if ( userlist[i] == username ) + { + delete(userlist[i]); + break; + } + } +} + +function add_user_form() +{ + var ul = document.getElementById('userlist'); + + if ( ul.parentNode.getElementsByTagName('form').length > 0 ) + { + return false; + } + + var theform = document.createElement('form'); + theform.action = 'javascript:void(0);'; + theform.onsubmit = function() + { + if ( this.username.value == '' || this.password.value == '' ) + { + alert('Please enter a username and password.'); + return false; + } + if ( draw_new_user(this.username.value, this.password.value) ) + { + this.parentNode.removeChild(this); + } + else + { + this.username.focus(); + } + + return false; + } + + theform.appendChild(document.createTextNode('user: ')); + + var i_user = document.createElement('input'); + i_user.type = 'text'; + i_user.name = 'username'; + i_user.size = '12'; + theform.appendChild(i_user); + + theform.appendChild(document.createTextNode(' pass: ')); + + var i_pass = document.createElement('input'); + i_pass.type = 'password'; + i_pass.name = 'password'; + i_pass.size = '12'; + theform.appendChild(i_pass); + + theform.appendChild(document.createTextNode(' ')); + + var i_sub = document.createElement('input'); + i_sub.type = 'submit'; + i_sub.value = 'Add'; + theform.appendChild(i_sub); + + ul.parentNode.appendChild(theform); + + i_user.focus(); +} + +window.onload = userlist_init; diff -r d62212462f9b -r 1b4288399b1f themes/grey/config.tpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/themes/grey/config.tpl Tue Sep 23 23:26:18 2008 -0400 @@ -0,0 +1,194 @@ +{** + * Template file for default Funky Monkey theme + * Web control interface script for Amarok + * Written by Dan Fuhry - 2008 + * + * 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. + *} + + + + + Greyhound: Configuration + + + + + + + + + « Return to playlist +
+ +
+ +
+ + + + + + {if $tried} + + + + {/if} + + + {if $needpass} + + + + + {/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Greyhound configuration
+ {if $success} +

{$success|nl2br}

+ {else} +

{$error|nl2br}

+ {/if} +
+ Current configuration password:
+ Please input the current configuration password to make changes below. +
+ +
+
+ + This controls whether Greyhound can be accessed from other computers on the network interface level. For the nerds, this + means that Greyhound will bind to 127.0.0.1 if unchecked or 0.0.0.0 if checked. + +
+ +
+
+ + Tick this option to enable full playback controls (recommended). Otherwise, Greyhound will just be a playlist viewer and + won't be able to do anything to control what Amarok is doing. + +
+ +
+
+ + If this is enabled, Greyhound will use fork() to allow serving multiple HTTP requests at the same time. It is recommended + that you enable this to improve performance. In some rare cases, this results in a large number of zombie processes and + sometimes locks up the server, so disable this if you're experiencing problems. + +
+ +
+ Authentication +
+
+ + Check this box to require a login to Greyhound's interface. The logins are cookie based, so make sure your browser supports + cookies and has them enabled before you enable this. You have to create at least one user for this to work. + +
+ +
+ User list
+ + This is the list of valid users for Greyhound. Passwords aren't encrypted in the config file to make editing easier. + +
+ {strip} + {foreach key=username item=password from=$users} + + {/foreach} + {/strip} + +
+ Config password
+ + Enter a password here to protect your configuration from being modified. + +
+ +
+ + +
+
+ +
+ + « Return to playlist + +
+ {include file="footer.tpl"} +
+ + + diff -r d62212462f9b -r 1b4288399b1f themes/grey/footer.tpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/themes/grey/footer.tpl Tue Sep 23 23:26:18 2008 -0400 @@ -0,0 +1,7 @@ + Powered by Greyhound v{$greyhound_version} + – + config + {if $use_auth} + – + log out + {/if} diff -r d62212462f9b -r 1b4288399b1f themes/grey/style.css --- a/themes/grey/style.css Tue Sep 23 23:26:15 2008 -0400 +++ b/themes/grey/style.css Tue Sep 23 23:26:18 2008 -0400 @@ -10,6 +10,9 @@ background-color: #262626; color: #ffffff; padding: 0 8px; +} + +body.playlist { background-image: url(images/playbar-shadow.gif); background-repeat: repeat-x; } @@ -18,6 +21,7 @@ padding: 1px; background-color: #b0b0b0; border: 1px solid #000000; + color: #c6c6c6; } div.tblholder table { @@ -28,14 +32,18 @@ background-color: #505050; } -tr.row1 td { +tr.row1 td, td.row1 { background-color: #383838; } -tr.row2 td { +tr.row2 td, td.row2 { background-color: #424242; } +tr.row3 td, td.row3 { + background-color: #3d3d3d; +} + tr.current td { background-color: #303030; color: #ffff00; @@ -144,3 +152,48 @@ div.poweredby a { color: #57608a; } + +ul#userlist a { + color: #ffff00; +} + +p.success, p.error { + text-align: center; + font-weight: bold; +} + +p.success { + color: #23a600; +} + +p.error { + color: #c71700; +} + +a.backlink { + display: block; + width: 150px; + color: #a0a0a0; + background-color: #404040; + padding: 5px; + margin: 10px 0 5px 0; + text-decoration: none; +} + +a.backlink:hover { + color: #c0c0c0; + background-color: #505050; +} + +div.greylogo { + width: 120px; + height: 33px; + background-image: url(images/greylogo.png); + background-repeat: no-repeat; + float: right; + margin: 5px 0; +} + +div.clearer { + clear: both; +} diff -r d62212462f9b -r 1b4288399b1f uiconfig.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uiconfig.php Tue Sep 23 23:26:18 2008 -0400 @@ -0,0 +1,176 @@ +header('HTTP/1.1 307 Temporary Redirect'); + $httpd->header('Location: /login'); + + return; + } + + $tried = false; + $success = false; + $needpass = false; + $error = false; + + // if a config password is set, make sure it matches. + $authed = false; + if ( empty($GLOBALS['configpass']) ) + { + $authed = true; + } + else + { + $needpass = true; + if ( isset($_POST['configpass']) && sha1($_POST['configpass']) === $GLOBALS['configpass'] ) + { + $authed = true; + $tried = true; + } + else if ( isset($_POST['configpass']) ) + { + $error = 'You didn\'t enter the right configuration password, so the changes weren\'t saved.'; + $tried = true; + } + } + + if ( $authed && isset($_POST['submit']) ) + { + $need_reboot = ( isset($_POST['public']) !== $GLOBALS['public'] || + isset($_POST['allow_fork']) !== $GLOBALS['allow_fork']); + + // compile the new config file + $public = ( isset($_POST['public']) ) ? 'true' : 'false'; + $allowcontrol = ( isset($_POST['allowcontrol']) ) ? 'true' : 'false'; + $allow_fork = ( isset($_POST['allow_fork']) ) ? 'true' : 'false'; + $use_auth = ( isset($_POST['use_auth']) ) ? 'true' : 'false'; + + // for auth_data, we're going to merge the data from POST with the current auth_data array. + $auth_data = $GLOBALS['auth_data']; + $auth_changed = false; + foreach ( $auth_data as $user => $pass ) + { + if ( !in_array($user, $_POST['users']) ) + { + $auth_changed = true; + unset($auth_data[$user]); + } + } + if ( isset($_POST['users_add']) ) + { + foreach ( $_POST['users_add'] as $user => $pass ) + { + $auth_changed = true; + $auth_data[$user] = $pass; + } + } + $auth_data = var_export_string($auth_data); + + $new_configpass = ( is_string($_POST['newconfigpass']) && $_POST['newconfigpass'] != '____________________' ) ? sha1($_POST['newconfigpass']) : $GLOBALS['configpass']; + + $config_file = <<If you changed your own password, you've been logged out so you'll need to log back in again." : ''; + if ( REBOOT_SUPPORT ) + { + $rebootblurb = $need_reboot ? "\nSince you changed some core configuration values, the Greyhound server has been restarted.\nIf Greyhound doesn't respond, wait 20 seconds and then restart it using Amarok's script manager." : ''; + } + else + { + $rebootblurb = $need_reboot ? "\nPlease restart Greyhound using Amarok's script manager for public IP and multithreading options to take effect." : ''; + } + $success = "Configuration changes successful.{$passblurb}{$rebootblurb}"; + $httpd->threader->ipc_send(array('action' => 'reloadconfig', 'propagate' => true)); + + if ( $need_reboot && REBOOT_SUPPORT ) + { + $addr = $GLOBALS['public'] ? '0.0.0.0' : '127.0.0.1'; + $fork = $GLOBALS['allow_fork']; + $httpd->reboot($addr, null, $fork); + } + } + } + + global $theme; + $iphone = ( ( strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone') || + strpos($_SERVER['HTTP_USER_AGENT'], 'iPod') || + strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') || + isset($_GET['m']) ) + && !isset($_GET['f']) + ); + $theme_id = ( $iphone ) ? 'iphone' : $theme; + $smarty = load_theme($theme_id); + + $smarty->assign('theme', $theme_id); + $smarty->assign('greyhound_version', GREY_VERSION); + $smarty->assign('tried', $tried); + $smarty->assign('success', $success); + $smarty->assign('needpass', $needpass); + $smarty->assign('use_auth', $use_auth); + $smarty->assign('public', $GLOBALS['public']); + $smarty->assign('allowcontrol', $GLOBALS['allowcontrol']); + $smarty->assign('allow_fork', $GLOBALS['allow_fork']); + $smarty->assign('use_auth', $GLOBALS['use_auth']); + $smarty->assign('users', $GLOBALS['auth_data']); + $smarty->assign('error', $error); + $smarty->display('config.tpl'); +}