diff options
author | Karl 'vollmerk' Vollmer <vollmer@ampache.org> | 2008-04-15 03:14:42 +0000 |
---|---|---|
committer | Karl 'vollmerk' Vollmer <vollmer@ampache.org> | 2008-04-15 03:14:42 +0000 |
commit | 669753d59d3b7acfb248e46daad174ed7414eb4a (patch) | |
tree | 1cb4505aa1bf878b470680ec85ab57f4e15c6955 | |
parent | 9504931c64a67156cde61c597ab4b111e3dc478f (diff) | |
download | ampache-669753d59d3b7acfb248e46daad174ed7414eb4a.tar.gz ampache-669753d59d3b7acfb248e46daad174ed7414eb4a.tar.bz2 ampache-669753d59d3b7acfb248e46daad174ed7414eb4a.zip |
first steps of a fix for the xml-rpc streaming and cataloging
-rwxr-xr-x | docs/CHANGELOG | 5 | ||||
-rw-r--r-- | lib/class/access.class.php | 2 | ||||
-rw-r--r-- | lib/class/catalog.class.php | 69 | ||||
-rw-r--r-- | lib/class/song.class.php | 2 | ||||
-rw-r--r-- | lib/class/stream.class.php | 2 | ||||
-rw-r--r-- | lib/class/vauth.class.php | 2 | ||||
-rw-r--r-- | lib/class/xmlrpcclient.class.php | 130 | ||||
-rw-r--r-- | lib/class/xmlrpcserver.class.php | 35 | ||||
-rw-r--r-- | play/index.php | 56 | ||||
-rw-r--r-- | templates/sidebar_localplay.inc.php | 11 |
10 files changed, 240 insertions, 74 deletions
diff --git a/docs/CHANGELOG b/docs/CHANGELOG index 92824d90..833f8e33 100755 --- a/docs/CHANGELOG +++ b/docs/CHANGELOG @@ -4,6 +4,11 @@ -------------------------------------------------------------------------- v.3.4-Beta3 + - Fixed seeking on random track, giving you a new track every + seek + - Added additional error reporting if localplay access / config + fails + - Give Admins Full Localplay Regardless - Fixed incorrect reference to ellipsis thresholds - Fixed page point not being remembered by the back button - Fixed naming restrictions on database name during install diff --git a/lib/class/access.class.php b/lib/class/access.class.php index 08736cfc..734c7d76 100644 --- a/lib/class/access.class.php +++ b/lib/class/access.class.php @@ -238,7 +238,7 @@ class Access { switch ($type) { case 'localplay': // Check their localplay_level - if (Config::get('localplay_level') >= $level) { + if (Config::get('localplay_level') >= $level OR $GLOBALS['user']->access >= '100') { return true; } else { diff --git a/lib/class/catalog.class.php b/lib/class/catalog.class.php index 3fb50cd6..2ec23dea 100644 --- a/lib/class/catalog.class.php +++ b/lib/class/catalog.class.php @@ -1211,45 +1211,27 @@ class Catalog { return false; } // end check for class - // first, glean out the information from the path about the server and remote path - // this can't contain the http - preg_match("/http:\/\/([^\/]+)\/*(.*)/", $this->path, $match); - $server = $match[1]; - $path = $match[2]; - - if ( ! $path ) { - $client = new xmlrpc_client("/server/xmlrpc.server.php", $server, 80); - } - else { - $client = new xmlrpc_client("/$path/server/xmlrpc.server.php", $server, 80); - } + // Handshake and get our token for this little conversation + $token = xmlRpcClient::ampache_handshake($this->path,$this->key); - // 6 that's right, the secret level because if you do have debug on most likely you're - // going to just crash your browser... sorry folks - if (Config::get('debug') AND Config::get('debug_level') == '6') { $client->setDebug(1); } + if (!$token) { + debug_event('XMLCLIENT','Error No Token returned'); + Error::display('general'); + return; + } - // Before we do anything else we need to do a handshake with the remote server - $timestamp = time(); - $handshake_key = md5($timestamp . $this->key); + // Figure out the host etc + preg_match("/http:\/\/([^\/\:]+):?(\d*)\/*(.*)/", $this->path, $match); + $server = $match['1']; + $port = $match['2'] ? intval($match['2']) : '80'; + $path = $match['3']; - $encoded_key = new xmlrpcval($handshake_key,"string"); - $timestamp = new xmlrpcval($timestamp,"int"); - $xmlrpc_message = new xmlrpcmsg('xmlrpcserver.handshake',array($encoded_key,$timestamp)); + $full_url = ltrim("/$path/server/xmlrpc.server.php",'/'); + $client = new xmlrpc_client($full_url,$server,$port); - // Send it off - $response = $client->send($xmlrpc_message,10); - if ($response->faultCode()) { - $error_msg = _("Error connecting to") . " " . $server . " " . _("Code") . ": " . $response->faultCode() . " " . _("Reason") . ": " . $response->faultString(); - debug_event('XMLCLIENT',$error_msg,'1'); - echo "<p class=\"error\">$error_msg</p>"; - return; - } - - $token = php_xmlrpc_decode($response->value()); - /* encode the variables we need to send over */ - $encoded_key = new xmlrpcval($token,"string"); - $encoded_path = new xmlrpcval(Config::get('web_path'),"string"); + $encoded_key = new xmlrpcval($token,'string'); + $encoded_path = new xmlrpcval(Config::get('web_path'),'string'); $xmlrpc_message = new xmlrpcmsg('xmlrpcserver.get_catalogs', array($encoded_key,$encoded_path)); $response = $client->send($xmlrpc_message,30); @@ -1287,6 +1269,9 @@ class Catalog { echo "<p>" . _('Completed updating remote catalog(s)') . ".</p><hr />\n"; flush(); + // Update the last update value + $this->update_last_update(); + return true; } // get_remote_catalog @@ -1298,9 +1283,9 @@ class Catalog { */ public function get_remote_song($client,$token,$start,$end) { - $encoded_start = new xmlrpcval($start,"int"); - $encoded_end = new xmlrpcval($end,"int"); - $encoded_key = new xmlrpcval($token,"string"); + $encoded_start = new xmlrpcval($start,'int'); + $encoded_end = new xmlrpcval($end,'int'); + $encoded_key = new xmlrpcval($token,'string'); $query_array = array($encoded_key,$encoded_start,$encoded_end); @@ -1329,14 +1314,11 @@ class Catalog { } // get_remote_song - /** * update_remote_catalog * actually updates from the remote data, takes an array of songs that are base64 encoded and parses them * @package XMLRPC * @catagory Client - * @todo This should be based off of seralize - * @todo some kind of cleanup of dead songs? */ function update_remote_catalog($data,$root_path) { @@ -1353,8 +1335,11 @@ class Catalog { $song->artist = self::check_artist($song->artist); $song->album = self::check_album($song->album,$song->year); $song->genre = self::check_genre($song->genre); - $song->file = $root_path . "/play/index.php?song=" . $data[12]; + $song->file = $root_path . "/play/index.php?song=" . $song->id; $song->catalog = $this->id; + + // Clear out the song id + unset($song->id); if (!$this->check_remote_song($song->file)) { $this->insert_remote_song($song); @@ -2158,8 +2143,6 @@ class Catalog { } //check_local_mp3 - - /*! @function import_m3u @discussion this takes m3u filename and then attempts diff --git a/lib/class/song.class.php b/lib/class/song.class.php index 23a3b658..e6caa24d 100644 --- a/lib/class/song.class.php +++ b/lib/class/song.class.php @@ -1,7 +1,7 @@ <?php /* - Copyright (c) 2001 - 2007 Ampache.org + Copyright (c) Ampache.org All rights reserved. This program is free software; you can redistribute it and/or diff --git a/lib/class/stream.class.php b/lib/class/stream.class.php index 87d34d2d..7582b9e2 100644 --- a/lib/class/stream.class.php +++ b/lib/class/stream.class.php @@ -1,7 +1,7 @@ <?php /* - Copyright (c) 2001 - 2007 Ampache.org + Copyright (c) Ampache.org All rights reserved. This program is free software; you can redistribute it and/or diff --git a/lib/class/vauth.class.php b/lib/class/vauth.class.php index 14f8b40d..b3892872 100644 --- a/lib/class/vauth.class.php +++ b/lib/class/vauth.class.php @@ -1,7 +1,7 @@ <?php /* - Copyright (c) 2001 - 2007 Ampache.org + Copyright (c) Ampache.org All Rights Reserved This program is free software; you can redistribute it and/or diff --git a/lib/class/xmlrpcclient.class.php b/lib/class/xmlrpcclient.class.php new file mode 100644 index 00000000..88174880 --- /dev/null +++ b/lib/class/xmlrpcclient.class.php @@ -0,0 +1,130 @@ +<?php +/* + + Copyright (c) Ampache.org + All rights reserved. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License v2 + as published by the Free Software Foundation. + + 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 more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/** + * xmlRpcClient + * This is the other half of the xmlrpcserver class, it Holds the different calls that Ampache might + * make that are xmlrpc'ie this does not include the API responses. + */ + +class xmlRpcClient { + + /** + * construtor + * not used + */ + private function __construct() { + + // Rien a faire + + } // constructor + + /** + * ampache_handshake + * This handshakes with ampache servers, this is used by the internal xml-rpc mojo + */ + public static function ampache_handshake($target_url,$key) { + + // Generate the client + $client = self::create_client($target_url); + + // 6 that's right, the secret level because if you do have debug on most likely you're + // going to just crash your browser... sorry folks + if (Config::get('debug') AND Config::get('debug_level') == '6') { $client->setDebug(1); } + + // Build our key + $timestamp = time(); + $handshake_key = md5($timestamp . $key); + + $encoded_key = new xmlrpcval($handshake_key,'string'); + $timestamp = new xmlrpcval($timestamp,'int'); + $xmlrpc_message = new xmlrpcmsg('xmlrpcserver.handshake',array($encoded_key,$timestamp)); + + // Send it off + $response = $client->send($xmlrpc_message,10); + if ($response->faultCode()) { + $error_msg = _('Error connecting to') . " " . $server . " " . _("Code") . ": " . $response->faultCode() . " " . _("Reason") . ": " . $response->faultString(); + debug_event('XMLCLIENT',$error_msg,'1'); + Error::add('general',$error_msg); + return; + } + + $token = php_xmlrpc_decode($response->value()); + + debug_event('XML-RPC',$token . ' returned from ' . $server,'3'); + + return $token; + + } // ampache_handshake + + /** + * ampache_create_stream_session + * This generates a new stream session, it takes a target_url and a token as generated by + * a ampache_handshake action + */ + public static function ampache_create_stream_session($target_url,$token) { + + $client = self::create_client($target_url); + + // 6 that's right, the secret level because if you do have debug on most likely you're + // going to just crash your browser... sorry folks + if (Config::get('debug') AND Config::get('debug_level') == '6') { $client->setDebug(1); } + + $encoded_key = new xmlrpcval($token,'string'); + $xmlrpc_message = new xmlrpcmsg('xmlrpcserver.create_stream_session',array($encoded_key)); + + $response = $client->send($xmlrpc_message,4); + + if ($response->faultCode() ) { + $error_msg = _("Error connecting to") . " " . $server . " " . _("Code") . ": " . $response->faultCode() . " " . + debug_event('XMLCLIENT',$error_msg,'1'); + return false; + } + + $sid = php_xmlrpc_decode($response->value()); + + debug_event('XML-RPC',$sid . ' stream session ID returned from ' . $server,'3'); + + return $sid; + + } // ampache_create_stream_session + + /** + * create_client + * This creates the xmlrpc client object from a URL + */ + public static function create_client($target_url) { + + // Figure out the host etc + preg_match("/http:\/\/([^\/\:]+):?(\d*)\/*(.*)/", $target_url, $match); + $server = $match['1']; + $port = $match['2'] ? intval($match['2']) : '80'; + $path = $match['3']; + + $full_url = ltrim("/$path/server/xmlrpc.server.php",'/'); + $client = new xmlrpc_client($full_url,$server,$port); + + return $client; + + } // create_client + +} // xmlRpcServer +?> diff --git a/lib/class/xmlrpcserver.class.php b/lib/class/xmlrpcserver.class.php index 5b6b3892..fc903aaf 100644 --- a/lib/class/xmlrpcserver.class.php +++ b/lib/class/xmlrpcserver.class.php @@ -1,7 +1,7 @@ <?php /* - Copyright (c) 2001 - 2007 Ampache.org + Copyright (c) Ampache.org All rights reserved. This program is free software; you can redistribute it and/or @@ -124,6 +124,36 @@ class xmlRpcServer { return new xmlrpcresp($encoded_array); } // get_songs + + /** + * create_stream_session + * This creates a new stream session and returns the SID in question, this requires a TOKEN as generated by the handshake + */ + public static function create_stream_session($xmlrpc_object) { + + // Pull out the key + $variable = $xmlrpc_object->getParam(0); + $key = $variable->scalarval(); + + // Check it and make sure we're super green + if (!vauth::session_exists('xml-rpc',$key)) { + debug_event('XMLSERVER','Error ' . $_SERVER['REMOTE_ADDR'] . ' with key ' . $key . ' does not match any ACLs','1'); + return new xmlrpcresp(0,'503','Key/IP Mis-match Access Denied'); + } + + $stream = new Stream(); + $stream->user_id = '-1'; + + if (!$stream->insert_session($key)) { + debug_event('XMLSERVER','Failed to create stream session','1'); + return new xmlrpcresp(0,'503','Failed to Create Stream Session','1'); + } + + $encoded_array = php_xmlrpc_encode($key); + + return new xmlrpcresp($encoded_array); + + } // create_stream_session /** * handshake @@ -156,7 +186,6 @@ class xmlRpcServer { // Build our encoded passphrase $md5pass = md5($timestamp . $row['key']); - if ($md5pass == $encoded_key) { $data['type'] = 'xml-rpc'; $data['username'] = 'System'; @@ -167,7 +196,7 @@ class xmlRpcServer { } // end while rows - return new xmlrpcresp(0,'503','Handshaek failure, Key/IP Incorrect'); + return new xmlrpcresp(0,'503','Handshake failure, Key/IP Incorrect'); } // handshake diff --git a/play/index.php b/play/index.php index 87d09fb5..e3df5584 100644 --- a/play/index.php +++ b/play/index.php @@ -1,7 +1,7 @@ <?php /* - Copyright (c) 2001 - 2008 Ampache.org + Copyright (c) Ampache.org All rights reserved. This program is free software; you can redistribute it and/or @@ -34,17 +34,26 @@ ob_end_clean(); $uid = scrub_in($_REQUEST['uid']); $song_id = scrub_in($_REQUEST['song']); $sid = scrub_in($_REQUEST['sid']); +$xml_rpc = scrub_in($_REQUEST['xml_rpc']); /* This is specifically for tmp playlist requests */ $demo_id = scrub_in($_REQUEST['demo_id']); $random = scrub_in($_REQUEST['random']); +// Parse byte range request +$n = sscanf($_SERVER['HTTP_RANGE'], "bytes=%d-%d",$start,$end); + /* First things first, if we don't have a uid/song_id stop here */ if (empty($song_id) && empty($demo_id) && empty($random)) { debug_event('no_song',"Error: No Song UID Specified, nothing to play",'2'); exit; } +// If we're XML-RPC and it's enabled, use system user +if (isset($xml_rpc) AND Config::get('xml_rpc') AND !isset($uid)) { + $uid = '-1'; +} + if (!isset($uid)) { debug_event('no_user','Error: No User specified','2'); exit; @@ -77,7 +86,7 @@ if (Config::get('require_session')) { $user->update_last_seen(); /* If we are in demo mode.. die here */ -if (Config::get('demo_mode') || !Access::check('interface','25')) { +if (Config::get('demo_mode') || (!Access::check('interface','25') AND !isset($xml_rpc))) { debug_event('access_denied',"Streaming Access Denied:" .Config::get('demo_mode') . "is the value of demo_mode. Current user level is " . $GLOBALS['user']->access,'3'); access_denied(); exit; @@ -127,8 +136,15 @@ if ($demo_id) { * if we are doing random let's pull the random object */ if ($random) { - $song_id = Random::get_single_song($_REQUEST['type']); -} + if (!isset($start)) { + $song_id = Random::get_single_song($_REQUEST['type']); + // Save this one incase we do a seek + $_SESSION['random']['last'] = $song_id; + } + else { + $song_id = $_SESSION['random']['last']; + } +} // if random /* Base Checks passed create the song object */ $song = new Song($song_id); @@ -166,25 +182,25 @@ if (Config::get('lock_songs')) { /* Check to see if this is a 'remote' catalog */ if ($catalog->catalog_type == 'remote') { - // redirect to the remote host's play path - /* Break Up the Web Path */ - preg_match("/http:\/\/([^\/]+)\/*(.*)/", Config::get('web_path'), $match); - $server = rawurlencode($match[1]); - $path = rawurlencode($match[2]); - $port = $_SERVER['SERVER_PORT']; - $ssl = ($_SERVER['HTTPS'] == 'on') ? '1' : '0'; - $catalog = $catalog->id; - - //Fixme: We should do a handshake here so we can pass a valid SID - - $extra_info = "&xml_rpc=1&xml_path=$path&xml_server=$server&xml_port=$port&ssl=$ssl&catalog=$catalog&sid=$sid"; + + preg_match("/(.+)\/play\/index.+/",$song->file,$match); + + $token = xmlRpcClient::ampache_handshake($match['1'],$catalog->key); + + // If we don't get anything back we failed and should bail now + if (!$token) { + debug_event('xmlrpc-stream','Error Unable to get Token from ' . $match['1'] . ' check target servers logs','1'); + exit; + } + + $sid = xmlRpcClient::ampache_create_stream_session($match['1'],$token); + + $extra_info = "&xml_rpc=1&sid=$sid"; header("Location: " . $song->file . $extra_info); debug_event('xmlrpc-stream',"Start XML-RPC Stream - " . $song->file . $extra_info,'5'); exit; } // end if remote catalog - - // make fread binary safe set_magic_quotes_runtime(0); @@ -239,10 +255,6 @@ if ($_GET['action'] == 'download' AND Config::get('download')) { } // if they are trying to download and they can - -// Parse byte range request -$n = sscanf($_SERVER['HTTP_RANGE'], "bytes=%d-%d",$start,$end); - // Generate browser class for sending headers $browser = new Browser(); header("Accept-Ranges: bytes" ); diff --git a/templates/sidebar_localplay.inc.php b/templates/sidebar_localplay.inc.php index 5e2e79ff..95313f4e 100644 --- a/templates/sidebar_localplay.inc.php +++ b/templates/sidebar_localplay.inc.php @@ -1,7 +1,7 @@ <?php /* - Copyright (c) 2001 - 2007 Ampache.org + Copyright (c) Ampache.org All rights reserved. This program is free software; you can redistribute it and/or @@ -21,7 +21,7 @@ ?> <ul class="sb2" id="sb_localplay"> -<?php if (Config::get('allow_localplay_playback') AND Config::get('localplay_controller') AND Access::check('localplay','5')) { ?> +<?php if ($server_allow = Config::get('allow_localplay_playback') AND $controller = Config::get('localplay_controller') AND $access_check = Access::check('localplay','5')) { ?> <?php // Little bit of work to be done here $localplay = new Localplay(Config::get('localplay_controller')); @@ -58,5 +58,12 @@ </li> <?php } else { ?> <li><h4><?php echo _('Localplay Disabled'); ?></h4></li> + <?php if (!$server_allow) { ?> + <li><?php echo _('Allow Localplay set to False'); ?></li> + <?php } elseif (!$controller) { ?> + <li><?php echo _('Localplay Controller Not Defined'); ?></li> + <?php } elseif (!$access_check) { ?> + <li><?php echo _('Access Denied'); ?></li> + <?php } ?> <?php } ?> </ul> |