summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarl 'vollmerk' Vollmer <vollmer@ampache.org>2007-12-18 05:31:54 +0000
committerKarl 'vollmerk' Vollmer <vollmer@ampache.org>2007-12-18 05:31:54 +0000
commit698f05d14f880eb4ec7866ec3a8416ee4d1f838f (patch)
treeafcfb18b11f13c1ba429612a94432fa0a64aa12c
parent74201cb6158db6448ebf5d8330ace6ad4a139693 (diff)
downloadampache-698f05d14f880eb4ec7866ec3a8416ee4d1f838f.tar.gz
ampache-698f05d14f880eb4ec7866ec3a8416ee4d1f838f.tar.bz2
ampache-698f05d14f880eb4ec7866ec3a8416ee4d1f838f.zip
fixed XML-RPC mostly, uses insecure/old authentication method, needs more work
-rwxr-xr-xdocs/CHANGELOG2
-rw-r--r--lib/class/catalog.class.php124
-rw-r--r--lib/class/song.class.php2
-rw-r--r--lib/class/xmlrpcserver.class.php142
-rw-r--r--lib/log.lib.php3
-rw-r--r--lib/ui.lib.php2
-rw-r--r--modules/xmlrpc/xmlrpc.inc9
-rw-r--r--modules/xmlrpc/xmlrpcs.inc4
-rw-r--r--server/xmlrpc.server.php50
-rw-r--r--templates/show_edit_access.inc.php4
10 files changed, 241 insertions, 101 deletions
diff --git a/docs/CHANGELOG b/docs/CHANGELOG
index ba3f4b8a..08e47e3a 100755
--- a/docs/CHANGELOG
+++ b/docs/CHANGELOG
@@ -4,6 +4,8 @@
--------------------------------------------------------------------------
v.3.4-Alpha4
+ - Fixed basic XML-RPC functionality, using insecure / old
+ authentication method needs more work
- Fixed it so that all errors should return an XML document when
using the XML API.
- Added Basic ShoutBox functionality, needs formating fixes
diff --git a/lib/class/catalog.class.php b/lib/class/catalog.class.php
index ce5c3e0d..d0388477 100644
--- a/lib/class/catalog.class.php
+++ b/lib/class/catalog.class.php
@@ -223,7 +223,7 @@ class Catalog {
$path = Dba::escape($data['path']);
// Make sure the path is readable/exists
- if (!is_readable($data['path'])) {
+ if (!is_readable($data['path']) AND $data['type'] == 'local') {
Error::add('general','Error: ' . scrub_out($data['path']) . ' is not readable or does not exist');
return false;
}
@@ -271,6 +271,13 @@ class Catalog {
*/
public function run_add($options) {
+ if ($this->catalog_type == 'remote') {
+ show_box_top(_('Running Remote Sync') . '. . .');
+ $this->get_remote_catalog($type=0);
+ show_box_bottom();
+ return true;
+ }
+
// Catalog Add start
$start_time = time();
@@ -1178,8 +1185,9 @@ class Catalog {
public function add_to_catalog() {
if ($this->catalog_type == 'remote') {
- echo _('Running Remote Update') . ". . .<br />";
+ show_box_top(_('Running Remote Update') . '. . .');
$this->get_remote_catalog($type=0);
+ show_box_bottom();
return true;
}
@@ -1242,14 +1250,10 @@ class Catalog {
/**
* get_remote_catalog
- * get a remote catalog and runs update if needed
- * @package XMLRPC
- * @catagory Client
- * @author Karl Vollmer
- * @todo Add support for something besides port 80
- * @todo Add a Pub/Private Key swap in here for extra security
+ * get a remote catalog and runs update if needed this requires
+ * the XML RPC stuff and a key to be passed
*/
- function get_remote_catalog($type=0) {
+ public function get_remote_catalog($type=0) {
/* Make sure the xmlrpc lib is loaded */
if (!class_exists('xmlrpc_client')) {
@@ -1273,13 +1277,15 @@ class Catalog {
/* encode the variables we need to send over */
$encoded_key = new xmlrpcval($this->key,"string");
- $encoded_path = new xmlrpcval(conf('web_path'),"string");
+ $encoded_path = new xmlrpcval(Config::get('web_path'),"string");
- $f = new xmlrpcmsg('remote_catalog_query', array($encoded_key,$encoded_path));
+ $xmlrpc_message = new xmlrpcmsg('xmlrpcserver.get_catalogs', array($encoded_key,$encoded_path));
- if (conf('debug')) { $client->setDebug(1); }
+ // 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); }
- $response = $client->send($f,30);
+ $response = $client->send($xmlrpc_message,30);
$value = $response->value();
if ( !$response->faultCode() ) {
@@ -1287,8 +1293,8 @@ class Catalog {
// Print out the catalogs we are going to sync
foreach ($data as $vars) {
- $catalog_name = $vars[0];
- $count = $vars[1];
+ $catalog_name = $vars['name'];
+ $count = $vars['count'];
print("<b>Reading Remote Catalog: $catalog_name ($count Songs)</b> [$this->path]<br />\n");
$total += $count;
}
@@ -1298,7 +1304,7 @@ class Catalog {
} // if we didn't get an error
else {
$error_msg = _("Error connecting to") . " " . $server . " " . _("Code") . ": " . $response->faultCode() . " " . _("Reason") . ": " . $response->faultString();
- debug_event('xmlrpc-client',$error_msg,'1','ampache-catalog');
+ debug_event('XMLCLIENT',$error_msg,'1');
echo "<p class=\"error\">$error_msg</p>";
return;
}
@@ -1324,11 +1330,8 @@ class Catalog {
* get_remote_song
* This functions takes a start and end point for gathering songs from a remote server. It is broken up
* in attempt to get around the problem of very large target catalogs
- * @package XMLRPC
- * @catagory Client
- * @todo Allow specificion of single catalog
*/
- function get_remote_song($client,$start,$end) {
+ public function get_remote_song($client,$start,$end) {
$encoded_start = new xmlrpcval($start,"int");
$encoded_end = new xmlrpcval($end,"int");
@@ -1336,12 +1339,12 @@ class Catalog {
$query_array = array($encoded_key,$encoded_start,$encoded_end);
- $f = new xmlrpcmsg('remote_song_query',$query_array);
+ $xmlrpc_message = new xmlrpcmsg('xmlrpcserver.get_songs',$query_array);
/* Depending upon the size of the target catalog this can be a very slow/long process */
set_time_limit(0);
// Sixty Second time out per chunk
- $response = $client->send($f,60);
+ $response = $client->send($xmlrpc_message,60);
$value = $response->value();
if ( !$response->faultCode() ) {
@@ -1353,7 +1356,7 @@ class Catalog {
}
else {
$error_msg = _('Error connecting to') . " " . $server . " " . _("Code") . ": " . $response->faultCode() . " " . _("Reason") . ": " . $response->faultString();
- debug_event('xmlrpc-client',$error_msg,'1','ampache-catalog');
+ debug_event('XMLCLIENT',$error_msg,'1');
echo "<p class=\"error\">$error_msg</p>";
}
@@ -1370,37 +1373,26 @@ class Catalog {
* @todo This should be based off of seralize
* @todo some kind of cleanup of dead songs?
*/
- function update_remote_catalog($songs,$root_path) {
+ function update_remote_catalog($data,$root_path) {
/*
We need to check the incomming songs
to see which ones need to be added
*/
- foreach ($songs as $song) {
+ foreach ($data as $serialized_song) {
// Prevent a timeout
set_time_limit(0);
- $song = base64_decode($song);
-
- $data = explode("::", $song);
-
- $new_song->artist = self::check_artist($data[0]);
- $new_song->album = self::check_album($data[1],$data[4]);
- $new_song->title = $data[2];
- $new_song->year = $data[4];
- $new_song->bitrate = $data[5];
- $new_song->rate = $data[6];
- $new_song->mode = $data[7];
- $new_song->size = $data[8];
- $new_song->time = $data[9];
- $new_song->track = $data[10];
- $new_song->genre = self::check_genre($data[11]);
- $new_song->file = $root_path . "/play/index.php?song=" . $data[12];
- $new_song->catalog = $this->id;
+ $song = unserialize($serialized_song);
+ $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->catalog = $this->id;
- if (!$this->check_remote_song($new_song->file)) {
- $this->insert_remote_song($new_song);
+ if (!$this->check_remote_song($song->file)) {
+ $this->insert_remote_song($song);
}
} // foreach new Songs
@@ -2113,22 +2105,22 @@ class Catalog {
} // insert_local_song
- /*!
- @function insert_remote_song
- @discussion takes the information gotten from XML-RPC and
- inserts it into the local database. The filename
- ends up being the url.
- */
- function insert_remote_song($song) {
+ /**
+ * insert_remote_song
+ * takes the information gotten from XML-RPC and
+ * inserts it into the local database. The filename
+ * ends up being the url.
+ */
+ public function insert_remote_song($song) {
- $url = sql_escape($song->file);
+ $url = Dba::escape($song->file);
$title = self::check_title($song->title);
- $title = sql_escape($title);
+ $title = Dba::escape($title);
$current_time = time();
$sql = "INSERT INTO song (file,catalog,album,artist,title,bitrate,rate,mode,size,time,track,genre,addition_time,year)" .
" VALUES ('$url','$song->catalog','$song->album','$song->artist','$title','$song->bitrate','$song->rate','$song->mode','$song->size','$song->time','$song->track','$song->genre','$current_time','$song->year')";
- $db_results = mysql_query($sql, dbh());
+ $db_results = Dba::query($sql);
if (!$db_results) {
debug_event('insert',"Unable to Add Remote $url -- $sql",'5','ampache-catalog');
@@ -2138,20 +2130,19 @@ class Catalog {
} // insert_remote_song
- /*!
- @function check_remote_song
- @discussion checks to see if a remote song exists in the database or not
- if it find a song it returns the UID
- */
- function check_remote_song($url) {
+ /**
+ * check_remote_song
+ * checks to see if a remote song exists in the database or not
+ * if it find a song it returns the UID
+ */
+ public function check_remote_song($url) {
- $url = sql_escape($url);
+ $url = Dba::escape($url);
- $sql = "SELECT id FROM song WHERE file='$url'";
-
- $db_results = mysql_query($sql, dbh());
+ $sql = "SELECT `id` FROM `song` WHERE `file`='$url'";
+ $db_results = Dba::query($sql);
- if (mysql_num_rows($db_results)) {
+ if (Dba::num_rows($db_results)) {
return true;
}
@@ -2159,12 +2150,11 @@ class Catalog {
} // check_remote_song
-
/**
* check_local_mp3
* Checks the song to see if it's there already returns true if found, false if not
*/
- function check_local_mp3($full_file, $gather_type='') {
+ public function check_local_mp3($full_file, $gather_type='') {
if ($gather_type == 'fast_add') {
$file_date = filemtime($full_file);
diff --git a/lib/class/song.class.php b/lib/class/song.class.php
index 4aa773fd..61ee2b93 100644
--- a/lib/class/song.class.php
+++ b/lib/class/song.class.php
@@ -659,7 +659,7 @@ class Song {
* and does a ton of formating on it creating f_??? variables on the current
* object
*/
- function format() {
+ public function format() {
$this->fill_ext_info();
diff --git a/lib/class/xmlrpcserver.class.php b/lib/class/xmlrpcserver.class.php
new file mode 100644
index 00000000..97f0208b
--- /dev/null
+++ b/lib/class/xmlrpcserver.class.php
@@ -0,0 +1,142 @@
+<?php
+/*
+
+ Copyright (c) 2001 - 2007 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.
+
+*/
+
+/**
+ * xmlRpcServer
+ * This class contains all the methods that the /server/xmlrpc.server.php will respond to
+ * to add a new method, just define a new public static function in here and it will be automagicaly
+ * populated to xmlrpcserver.<FUNCTION> in /server/xmlrpc.server.php
+ */
+
+class xmlRpcServer {
+
+ /**
+ * get_catalogs
+ * This returns a list of the current non-remote catalogs hosted on this Ampache instance
+ * It requires a key be passed as the first element
+ * //FIXME: USE TOKEN!
+ */
+ public static function get_catalogs($xmlrpc_object) {
+
+ // Pull out the key
+ $variable = $xmlrpc_object->getParam(0);
+ $key = $variable->scalarval();
+
+ // Check it and make sure we're super green
+ if (!Access::check_network('rpc',$_SERVER['REMOTE_ADDR'],'','5',$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');
+ }
+
+ // Go ahead and gather up the information they are legit
+ $results = array();
+
+ $sql = "SELECT `catalog`.`name`,COUNT(`song`.`id`) AS `count`,`catalog`.`id` AS `catalog_id` FROM `catalog` ".
+ "LEFT JOIN `song` ON `catalog`.`id`=`song`.`catalog` WHERE `catalog`.`catalog_type`='local' " .
+ "GROUP BY `catalog`.`id`";
+ $db_results = Dba::query($sql);
+
+ while ($row = Dba::fetch_assoc($db_results)) {
+ $results[] = $row;
+ }
+
+ // We need to set time limit at this point as who know how long this data is going to take
+ // to return to the client
+ set_time_limit(0);
+
+ $encoded_array = php_xmlrpc_encode($results);
+ debug_event('XMLSERVER','Returning data about ' . count($results) . ' catalogs to ' . $_SERVER['REMOTE_ADDR'],'5');
+
+ return new xmlrpcresp($encoded_array);
+
+ } // get_catalogs
+
+ /**
+ * get_songs
+ * This is a basic function to return all of the song data in a serialized format. It takes a start and end point
+ * as well as the TOKEN for auth mojo
+ * //FIXME: USE TOKEN!
+ */
+ public static function get_songs($xmlrpc_object) {
+
+ // We're going to be here a while
+ set_time_limit(0);
+
+ // Pull out the key
+ $variable = $xmlrpc_object->getParam(0);
+ $key = $variable->scalarval();
+
+ // Check it and make sure we're super green
+ if (!Access::check_network('rpc',$_SERVER['REMOTE_ADDR'],'','5',$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');
+ }
+
+ // Now pull out the start and end
+ $start = intval($xmlrpc_object->params['1']->me['int']);
+ $end = intval($xmlrpc_object->params['2']->me['int']);
+
+ // Get Catalogs first
+ $sql = "SELECT `catalog`.`id` FROM `catalog` WHERE `catalog`.`catalog_type`='local'";
+ $db_results = Dba::query($sql);
+
+ while ($row = Dba::fetch_assoc($db_results)) {
+ $where_sql .= "`song`.`catalog`='" . $row['id'] . "' OR";
+ }
+
+ $where_sql = rtrim($where_sql,'OR');
+
+ $sql = "SELECT `song`.`id` FROM `song` WHERE `song`.`enabled`='1' AND ($where_sql) LIMIT $start,$end";
+ $db_results = Dba::query($sql);
+
+ while ($row = Dba::fetch_assoc($db_results)) {
+ $song = new Song($row['id']);
+ $song->fill_ext_info();
+ $song->album = $song->get_album_name();
+ $song->artist = $song->get_artist_name();
+ $song->genre = $song->get_genre_name();
+
+ $output = serialize($song);
+ $results[] = $output;
+ } // end while
+
+ $encoded_array = php_xmlrpc_encode($results);
+ debug_event('XMLSERVER','Encoded ' . count($results) . ' songs (' . $start . ',' . $end . ')','5');
+
+ return new xmlrpcresp($encoded_array);
+
+ } // get_songs
+
+ /**
+ * handshake
+ * This should be run before any other XMLRPC actions, it checks the KEY encoded with a timestamp then returns a valid TOKEN to be
+ * used in all further communication
+ */
+ public static function handshake($xmlrpc_object) {
+
+ // Pull out the params
+ $encoded_key = $xmlrpc_object->params['0']->me['string'];
+ $timestamp = $xmlrpc_object->params['0']->me['int'];
+
+ } // handshake
+
+} // xmlRpcServer
+?>
diff --git a/lib/log.lib.php b/lib/log.lib.php
index 63c2ba4a..83786c67 100644
--- a/lib/log.lib.php
+++ b/lib/log.lib.php
@@ -84,7 +84,8 @@ function ampache_error_handler($errno, $errstr, $errfile, $errline) {
* Yea now getid3() spews errors I love it :(
*/
if (strstr($errstr,"var: Deprecated. Please use the public/private/protected modifiers") OR
- strstr($errstr,"getimagesize() [") OR strstr($errstr,"Non-static method getid3")) {
+ strstr($errstr,"getimagesize() [") OR strstr($errstr,"Non-static method getid3") OR
+ strstr($errstr,"Assigning the return value of new by reference is deprecated")) {
return false;
}
diff --git a/lib/ui.lib.php b/lib/ui.lib.php
index 72203091..ad51b148 100644
--- a/lib/ui.lib.php
+++ b/lib/ui.lib.php
@@ -725,7 +725,7 @@ function show_catalog_select($name='catalog',$catalog_id=0,$style='') {
function show_user_select($name,$selected='',$style='') {
echo "<select name=\"$name\" style=\"$style\">\n";
- echo "\t<option value=\"\">" . _('None') . "</option>\n";
+ echo "\t<option value=\"\">" . _('All') . "</option>\n";
$sql = "SELECT `id`,`username`,`fullname` FROM `user` ORDER BY `fullname`";
$db_results = Dba::query($sql);
diff --git a/modules/xmlrpc/xmlrpc.inc b/modules/xmlrpc/xmlrpc.inc
index 0c3702e9..da096c1b 100644
--- a/modules/xmlrpc/xmlrpc.inc
+++ b/modules/xmlrpc/xmlrpc.inc
@@ -1904,7 +1904,7 @@ $cp1252_to_xmlent =
if ($valtyp == '')
{
// user did not declare type of response value: try to guess it
- if (is_object($this->val) && is_a($this->val, 'xmlrpcval'))
+ if (is_object($this->val) && $this->val instanceof xmlrpcval)
{
$this->valtyp = 'xmlrpcvals';
}
@@ -1997,7 +1997,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
}
else
{
- if(!is_object($this->val) || !is_a($this->val, 'xmlrpcval'))
+ if(!is_object($this->val) || !$this->val instanceof xmlrpcval)
{
if (is_string($this->val) && $this->valtyp == 'xml')
{
@@ -2136,7 +2136,8 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
function addParam($par)
{
// add check: do not add to self params which are not xmlrpcvals
- if(is_object($par) && is_a($par, 'xmlrpcval'))
+ $is_instance = $par instanceof xmlrpcval;
+ if(is_object($par) && $is_instance)
{
$this->params[]=$par;
return true;
@@ -3637,4 +3638,4 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
}
}
-?> \ No newline at end of file
+?>
diff --git a/modules/xmlrpc/xmlrpcs.inc b/modules/xmlrpc/xmlrpcs.inc
index 661a1b4b..d363bf7d 100644
--- a/modules/xmlrpc/xmlrpcs.inc
+++ b/modules/xmlrpc/xmlrpcs.inc
@@ -1061,7 +1061,7 @@
{
$r = call_user_func($func, $m);
}
- if (!is_a($r, 'xmlrpcresp'))
+ if (!$r instanceof xmlrpcresp)
{
error_log("XML-RPC: xmlrpc_server::execute: function $func registered as method handler does not return an xmlrpcresp object");
if (is_a($r, 'xmlrpcval'))
@@ -1169,4 +1169,4 @@
print $r->serialize();
}
}
-?> \ No newline at end of file
+?>
diff --git a/server/xmlrpc.server.php b/server/xmlrpc.server.php
index 5487ddec..ab6d9e3c 100644
--- a/server/xmlrpc.server.php
+++ b/server/xmlrpc.server.php
@@ -1,7 +1,7 @@
<?php
/*
- Copyright 2001 - 2006 Ampache.org
+ Copyright 2001 - 2007 Ampache.org
All Rights Reserved
This program is free software; you can redistribute it and/or
@@ -22,32 +22,36 @@
define('NO_SESSION','1');
require_once('../lib/init.php');
-if (conf('xml_rpc')) {
- require_once(conf('prefix') . "/modules/xmlrpc/xmlrpcs.inc");
- require_once(conf('prefix') . "/modules/xmlrpc/xmlrpc.inc");
-}
-else { exit(); }
+/* Set the correct headers */
+header("Content-type: text/xml; charset=" . Config::get('site_charset'));
+header("Content-Disposition: attachment; filename=xmlrpc-server.xml");
-/* Setup the vars we are going to need */
-$access = new Access();
+if (Config::get('xml_rpc')) {
+ require_once Config::get('prefix') . "/modules/xmlrpc/xmlrpcs.inc";
+ require_once Config::get('prefix') . "/modules/xmlrpc/xmlrpc.inc";
+}
+else {
+ debug_event('DENIED','Attempted to Access XMLRPC server with xml_rpc disabled','1');
+ exit();
+}
// ** check that the remote server has access to this catalog
-if ($access->check('init-xml-rpc',$_SERVER['REMOTE_ADDR'],'','5','')) {
+if (Access::check_network('init-rpc',$_SERVER['REMOTE_ADDR'],'','5','')) {
- /* Setup Possible Actions */
- $methods['remote_catalog_query'] = array('function' => 'remote_catalog_query');
- $methods['remote_song_query'] = array('function' => 'remote_song_query');
- $methods['remote_session_verify'] = array('function' => 'remote_session_verify');
+ // Define an array of classes we need to pull from for the
+ $classes = array('xmlRpcServer');
- $s = new xmlrpc_server($methods);
-}
-else {
- // Access Denied... Sucka!!
- $methods['remote_catalog_query'] = array('function' => 'remote_server_denied');
- $methods['remote_song_query'] = array('function' => 'remote_server_denied');
- $methods['remote_session_verify'] = array('function' => 'remote_server_denied');
-
- $s = new xmlrpc_server($methods);
-}
+ foreach ($classes as $class) {
+ $methods = get_class_methods($class);
+
+ foreach ($methods as $method) {
+ $name = strtolower($class) . '.' . strtolower($method);
+ $functions[$name] = array('function'=>$class . '::' . $method);
+ }
+
+ } // end foreach of classes
+
+ $server = new xmlrpc_server($functions);
+} // test for ACL
?>
diff --git a/templates/show_edit_access.inc.php b/templates/show_edit_access.inc.php
index 676a8570..c4825d2f 100644
--- a/templates/show_edit_access.inc.php
+++ b/templates/show_edit_access.inc.php
@@ -43,12 +43,14 @@
<td><?php echo _('Start IP Address'); ?>:</td>
<td>
<input type="text" name="start" value="<?php echo int2ip($access->start); ?>" size="20" maxlength="15" />
+ <span class="information">(0.0.0.0)</span>
</td>
</tr>
<tr>
<td><?php echo _('End IP Address'); ?>:</td>
<td>
<input type="text" name="end" value="<?php echo int2ip($access->end); ?>" size="20" maxlength="15" />
+ <span class="information">(0.0.0.0)</span>
</td>
</tr>
<tr>
@@ -57,14 +59,12 @@
<?php show_user_select('user',$access->user); ?>
</td>
</tr>
-<?php if ($access->type == 'rpc') { ?>
<tr>
<td><?php echo _('Remote Key'); ?></td>
<td>
<input type="text" name="key" value="<?php echo scrub_out($access->key); ?>" size="32" maxlength="32" />
</td>
</tr>
-<?php } ?>
</tr>
<tr>
<td><?php echo _('Level'); ?>:</td>