home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / tmp / PEAR-1.7.1 / PEAR / Command / Channels.php < prev    next >
Encoding:
PHP Script  |  2008-02-15  |  29.6 KB  |  738 lines

  1. <?php
  2. // /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. /**
  4.  * PEAR_Command_Channels (list-channels, update-channels, channel-delete, channel-add,
  5.  * channel-update, channel-info, channel-alias, channel-discover commands)
  6.  *
  7.  * PHP versions 4 and 5
  8.  *
  9.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  10.  * that is available through the world-wide-web at the following URI:
  11.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  12.  * the PHP License and are unable to obtain it through the web, please
  13.  * send a note to license@php.net so we can mail you a copy immediately.
  14.  *
  15.  * @category   pear
  16.  * @package    PEAR
  17.  * @author     Stig Bakken <ssb@php.net>
  18.  * @author     Greg Beaver <cellog@php.net>
  19.  * @copyright  1997-2008 The PHP Group
  20.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  21.  * @version    CVS: $Id: Channels.php,v 1.57 2008/01/03 20:26:36 cellog Exp $
  22.  * @link       http://pear.php.net/package/PEAR
  23.  * @since      File available since Release 1.4.0a1
  24.  */
  25.  
  26. /**
  27.  * base class
  28.  */
  29. require_once 'PEAR/Command/Common.php';
  30.  
  31. /**
  32.  * PEAR commands for managing channels.
  33.  *
  34.  * @category   pear
  35.  * @package    PEAR
  36.  * @author     Greg Beaver <cellog@php.net>
  37.  * @copyright  1997-2008 The PHP Group
  38.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  39.  * @version    Release: 1.7.1
  40.  * @link       http://pear.php.net/package/PEAR
  41.  * @since      Class available since Release 1.4.0a1
  42.  */
  43. class PEAR_Command_Channels extends PEAR_Command_Common
  44. {
  45.     // {{{ properties
  46.  
  47.     var $commands = array(
  48.         'list-channels' => array(
  49.             'summary' => 'List Available Channels',
  50.             'function' => 'doList',
  51.             'shortcut' => 'lc',
  52.             'options' => array(),
  53.             'doc' => '
  54. List all available channels for installation.
  55. ',
  56.             ),
  57.         'update-channels' => array(
  58.             'summary' => 'Update the Channel List',
  59.             'function' => 'doUpdateAll',
  60.             'shortcut' => 'uc',
  61.             'options' => array(),
  62.             'doc' => '
  63. List all installed packages in all channels.
  64. '
  65.             ),
  66.         'channel-delete' => array(
  67.             'summary' => 'Remove a Channel From the List',
  68.             'function' => 'doDelete',
  69.             'shortcut' => 'cde',
  70.             'options' => array(),
  71.             'doc' => '<channel name>
  72. Delete a channel from the registry.  You may not
  73. remove any channel that has installed packages.
  74. '
  75.             ),
  76.         'channel-add' => array(
  77.             'summary' => 'Add a Channel',
  78.             'function' => 'doAdd',
  79.             'shortcut' => 'ca',
  80.             'options' => array(),
  81.             'doc' => '<channel.xml>
  82. Add a private channel to the channel list.  Note that all
  83. public channels should be synced using "update-channels".
  84. Parameter may be either a local file or remote URL to a
  85. channel.xml.
  86. '
  87.             ),
  88.         'channel-update' => array(
  89.             'summary' => 'Update an Existing Channel',
  90.             'function' => 'doUpdate',
  91.             'shortcut' => 'cu',
  92.             'options' => array(
  93.                 'force' => array(
  94.                     'shortopt' => 'f',
  95.                     'doc' => 'will force download of new channel.xml if an existing channel name is used',
  96.                     ),
  97.                 'channel' => array(
  98.                     'shortopt' => 'c',
  99.                     'arg' => 'CHANNEL',
  100.                     'doc' => 'will force download of new channel.xml if an existing channel name is used',
  101.                     ),
  102. ),
  103.             'doc' => '[<channel.xml>|<channel name>]
  104. Update a channel in the channel list directly.  Note that all
  105. public channels can be synced using "update-channels".
  106. Parameter may be a local or remote channel.xml, or the name of
  107. an existing channel.
  108. '
  109.             ),
  110.         'channel-info' => array(
  111.             'summary' => 'Retrieve Information on a Channel',
  112.             'function' => 'doInfo',
  113.             'shortcut' => 'ci',
  114.             'options' => array(),
  115.             'doc' => '<package>
  116. List the files in an installed package.
  117. '
  118.             ),
  119.         'channel-alias' => array(
  120.             'summary' => 'Specify an alias to a channel name',
  121.             'function' => 'doAlias',
  122.             'shortcut' => 'cha',
  123.             'options' => array(),
  124.             'doc' => '<channel> <alias>
  125. Specify a specific alias to use for a channel name.
  126. The alias may not be an existing channel name or
  127. alias.
  128. '
  129.             ),
  130.         'channel-discover' => array(
  131.             'summary' => 'Initialize a Channel from its server',
  132.             'function' => 'doDiscover',
  133.             'shortcut' => 'di',
  134.             'options' => array(),
  135.             'doc' => '[<channel.xml>|<channel name>]
  136. Initialize a channel from its server and create a local channel.xml.
  137. If <channel name> is in the format "<username>:<password>@<channel>" then
  138. <username> and <password> will be set as the login username/password for
  139. <channel>. Use caution when passing the username/password in this way, as
  140. it may allow other users on your computer to briefly view your username/
  141. password via the system\'s process list.
  142. '
  143.             ),
  144.         );
  145.  
  146.     // }}}
  147.     // {{{ constructor
  148.  
  149.     /**
  150.      * PEAR_Command_Registry constructor.
  151.      *
  152.      * @access public
  153.      */
  154.     function PEAR_Command_Channels(&$ui, &$config)
  155.     {
  156.         parent::PEAR_Command_Common($ui, $config);
  157.     }
  158.  
  159.     // }}}
  160.  
  161.     // {{{ doList()
  162.     
  163.     function _sortChannels($a, $b)
  164.     {
  165.         return strnatcasecmp($a->getName(), $b->getName());
  166.     }
  167.  
  168.     function doList($command, $options, $params)
  169.     {
  170.         $reg = &$this->config->getRegistry();
  171.         $registered = $reg->getChannels();
  172.         usort($registered, array(&$this, '_sortchannels'));
  173.         $i = $j = 0;
  174.         $data = array(
  175.             'caption' => 'Registered Channels:',
  176.             'border' => true,
  177.             'headline' => array('Channel', 'Summary')
  178.             );
  179.         foreach ($registered as $channel) {
  180.             $data['data'][] = array($channel->getName(),
  181.                                       $channel->getSummary());
  182.         }
  183.         if (count($registered)==0) {
  184.             $data = '(no registered channels)';
  185.         }
  186.         $this->ui->outputData($data, $command);
  187.         return true;
  188.     }
  189.     
  190.     function doUpdateAll($command, $options, $params)
  191.     {
  192.         $reg = &$this->config->getRegistry();
  193.         $channels = $reg->getChannels();
  194.  
  195.         $success = true;
  196.         foreach ($channels as $channel) {
  197.             if ($channel->getName() != '__uri') {
  198.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  199.                 $err = $this->doUpdate('channel-update',
  200.                                           $options,
  201.                                           array($channel->getName()));
  202.                 if (PEAR::isError($err)) {
  203.                     $this->ui->outputData($err->getMessage(), $command);
  204.                     $success = false;
  205.                 } else {
  206.                     $success &= $err;
  207.                 }
  208.             }
  209.         }
  210.         return $success;
  211.     }
  212.     
  213.     function doInfo($command, $options, $params)
  214.     {
  215.         if (sizeof($params) != 1) {
  216.             return $this->raiseError("No channel specified");
  217.         }
  218.         $reg = &$this->config->getRegistry();
  219.         $channel = strtolower($params[0]);
  220.         if ($reg->channelExists($channel)) {
  221.             $chan = $reg->getChannel($channel);
  222.             if (PEAR::isError($chan)) {
  223.                 return $this->raiseError($chan);
  224.             }
  225.         } else {
  226.             if (strpos($channel, '://')) {
  227.                 $downloader = &$this->getDownloader();
  228.                 $tmpdir = $this->config->get('temp_dir');
  229.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  230.                 $loc = $downloader->downloadHttp($channel, $this->ui, $tmpdir);
  231.                 PEAR::staticPopErrorHandling();
  232.                 if (PEAR::isError($loc)) {
  233.                     return $this->raiseError('Cannot open "' . $channel .
  234.                         '" (' . $loc->getMessage() . ')');
  235.                 } else {
  236.                     $contents = implode('', file($loc));
  237.                 }
  238.             } else {
  239.                 if (file_exists($params[0])) {
  240.                     $fp = fopen($params[0], 'r');
  241.                     if (!$fp) {
  242.                         return $this->raiseError('Cannot open "' . $params[0] . '"');
  243.                     }
  244.                 } else {
  245.                     return $this->raiseError('Unknown channel "' . $channel . '"');
  246.                 }
  247.                 $contents = '';
  248.                 while (!feof($fp)) {
  249.                     $contents .= fread($fp, 1024);
  250.                 }
  251.                 fclose($fp);
  252.             }
  253.             if (!class_exists('PEAR_ChannelFile')) {
  254.                 require_once 'PEAR/ChannelFile.php';
  255.             }
  256.             $chan = new PEAR_ChannelFile;
  257.             $chan->fromXmlString($contents);
  258.             $chan->validate();
  259.             if ($errs = $chan->getErrors(true)) {
  260.                 foreach ($errs as $err) {
  261.                     $this->ui->outputData($err['level'] . ': ' . $err['message']);
  262.                 }
  263.                 return $this->raiseError('Channel file "' . $params[0] . '" is not valid');
  264.             }
  265.         }
  266.         if ($chan) {
  267.             $channel = $chan->getName();
  268.             $caption = 'Channel ' . $channel . ' Information:';
  269.             $data1 = array(
  270.                 'caption' => $caption,
  271.                 'border' => true);
  272.             $data1['data']['server'] = array('Name and Server', $chan->getName());
  273.             if ($chan->getAlias() != $chan->getName()) {
  274.                 $data1['data']['alias'] = array('Alias', $chan->getAlias());
  275.             }
  276.             $data1['data']['summary'] = array('Summary', $chan->getSummary());
  277.             $validate = $chan->getValidationPackage();
  278.             $data1['data']['vpackage'] = array('Validation Package Name', $validate['_content']);
  279.             $data1['data']['vpackageversion'] =
  280.                 array('Validation Package Version', $validate['attribs']['version']);
  281.             $d = array();
  282.             $d['main'] = $data1;
  283.  
  284.             $data['data'] = array();
  285.             $data['caption'] = 'Server Capabilities';
  286.             $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
  287.             $capabilities = $chan->getFunctions('xmlrpc');
  288.             $soaps = $chan->getFunctions('soap');
  289.             if ($capabilities || $soaps || $chan->supportsREST()) {
  290.                 if ($capabilities) {
  291.                     if (!isset($capabilities[0])) {
  292.                         $capabilities = array($capabilities);
  293.                     }
  294.                     foreach ($capabilities as $protocol) {
  295.                         $data['data'][] = array('xmlrpc', $protocol['attribs']['version'],
  296.                             $protocol['_content']);
  297.                     }
  298.                 }
  299.                 if ($soaps) {
  300.                     if (!isset($soaps[0])) {
  301.                         $soaps = array($soaps);
  302.                     }
  303.                     foreach ($soaps as $protocol) {
  304.                         $data['data'][] = array('soap', $protocol['attribs']['version'],
  305.                             $protocol['_content']);
  306.                     }
  307.                 }
  308.                 if ($chan->supportsREST()) {
  309.                     $funcs = $chan->getFunctions('rest');
  310.                     if (!isset($funcs[0])) {
  311.                         $funcs = array($funcs);
  312.                     }
  313.                     foreach ($funcs as $protocol) {
  314.                         $data['data'][] = array('rest', $protocol['attribs']['type'],
  315.                             $protocol['_content']); 
  316.                     }
  317.                 }
  318.             } else {
  319.                 $data['data'][] = array('No supported protocols');
  320.             }
  321.             $d['protocols'] = $data;
  322.             $data['data'] = array();
  323.             $mirrors = $chan->getMirrors();
  324.             if ($mirrors) {
  325.                 $data['caption'] = 'Channel ' . $channel . ' Mirrors:';
  326.                 unset($data['headline']);
  327.                 foreach ($mirrors as $mirror) {
  328.                     $data['data'][] = array($mirror['attribs']['host']);
  329.                     $d['mirrors'] = $data;
  330.                 }
  331.                 foreach ($mirrors as $i => $mirror) {
  332.                     $data['data'] = array();
  333.                     $data['caption'] = 'Mirror ' . $mirror['attribs']['host'] . ' Capabilities';
  334.                     $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
  335.                     $capabilities = $chan->getFunctions('xmlrpc', $mirror['attribs']['host']);
  336.                     $soaps = $chan->getFunctions('soap', $mirror['attribs']['host']);
  337.                     if ($capabilities || $soaps || $chan->supportsREST($mirror['attribs']['host'])) {
  338.                         if ($capabilities) {
  339.                             if (!isset($capabilities[0])) {
  340.                                 $capabilities = array($capabilities);
  341.                             }
  342.                             foreach ($capabilities as $protocol) {
  343.                                 $data['data'][] = array('xmlrpc', $protocol['attribs']['version'],
  344.                                     $protocol['_content']);
  345.                             }
  346.                         }
  347.                         if ($soaps) {
  348.                             if (!isset($soaps[0])) {
  349.                                 $soaps = array($soaps);
  350.                             }
  351.                             foreach ($soaps as $protocol) {
  352.                                 $data['data'][] = array('soap', $protocol['attribs']['version'],
  353.                                     $protocol['_content']);
  354.                             }
  355.                         }
  356.                         if ($chan->supportsREST($mirror['attribs']['host'])) {
  357.                             $funcs = $chan->getFunctions('rest', $mirror['attribs']['host']);
  358.                             if (!isset($funcs[0])) {
  359.                                 $funcs = array($funcs);
  360.                             }
  361.                             foreach ($funcs as $protocol) {
  362.                                 $data['data'][] = array('rest', $protocol['attribs']['type'],
  363.                                     $protocol['_content']); 
  364.                             }
  365.                         }
  366.                     } else {
  367.                         $data['data'][] = array('No supported protocols');
  368.                     }
  369.                     $d['mirrorprotocols' . $i] = $data;
  370.                 }
  371.             }
  372.             $this->ui->outputData($d, 'channel-info');
  373.         } else {
  374.             return $this->raiseError('Serious error: Channel "' . $params[0] .
  375.                 '" has a corrupted registry entry');
  376.         }
  377.     }
  378.  
  379.     // }}}
  380.     
  381.     function doDelete($command, $options, $params)
  382.     {
  383.         if (sizeof($params) != 1) {
  384.             return $this->raiseError('channel-delete: no channel specified');
  385.         }
  386.         $reg = &$this->config->getRegistry();
  387.         if (!$reg->channelExists($params[0])) {
  388.             return $this->raiseError('channel-delete: channel "' . $params[0] . '" does not exist');
  389.         }
  390.         $channel = $reg->channelName($params[0]);
  391.         if ($channel == 'pear.php.net') {
  392.             return $this->raiseError('Cannot delete the pear.php.net channel');
  393.         }
  394.         if ($channel == 'pecl.php.net') {
  395.             return $this->raiseError('Cannot delete the pecl.php.net channel');
  396.         }
  397.         if ($channel == '__uri') {
  398.             return $this->raiseError('Cannot delete the __uri pseudo-channel');
  399.         }
  400.         if (PEAR::isError($err = $reg->listPackages($channel))) {
  401.             return $err;
  402.         }
  403.         if (count($err)) {
  404.             return $this->raiseError('Channel "' . $channel .
  405.                 '" has installed packages, cannot delete');
  406.         }
  407.         if (!$reg->deleteChannel($channel)) {
  408.             return $this->raiseError('Channel "' . $channel . '" deletion failed');
  409.         } else {
  410.             $this->config->deleteChannel($channel);
  411.             $this->ui->outputData('Channel "' . $channel . '" deleted', $command);
  412.         }
  413.     }
  414.  
  415.     function doAdd($command, $options, $params)
  416.     {
  417.         if (sizeof($params) != 1) {
  418.             return $this->raiseError('channel-add: no channel file specified');
  419.         }
  420.         if (strpos($params[0], '://')) {
  421.             $downloader = &$this->getDownloader();
  422.             $tmpdir = $this->config->get('temp_dir');
  423.             if (!file_exists($tmpdir)) {
  424.                 require_once 'System.php';
  425.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  426.                 $err = System::mkdir(array('-p', $tmpdir));
  427.                 PEAR::staticPopErrorHandling();
  428.                 if (PEAR::isError($err)) {
  429.                     return $this->raiseError('channel-add: temp_dir does not exist: "' .
  430.                         $tmpdir . 
  431.                         '" - You can change this location with "pear config-set temp_dir"');
  432.                 }
  433.             }
  434.             if (!is_writable($tmpdir)) {
  435.                 return $this->raiseError('channel-add: temp_dir is not writable: "' .
  436.                     $tmpdir . 
  437.                     '" - You can change this location with "pear config-set temp_dir"');
  438.             }
  439.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  440.             $loc = $downloader->downloadHttp($params[0], $this->ui, $tmpdir, null, false);
  441.             PEAR::staticPopErrorHandling();
  442.             if (PEAR::isError($loc)) {
  443.                 return $this->raiseError('channel-add: Cannot open "' . $params[0] .
  444.                     '" (' . $loc->getMessage() . ')');
  445.             } else {
  446.                 list($loc, $lastmodified) = $loc;
  447.                 $contents = implode('', file($loc));
  448.             }
  449.         } else {
  450.             $lastmodified = $fp = false;
  451.             if (file_exists($params[0])) {
  452.                 $fp = fopen($params[0], 'r');
  453.             }
  454.             if (!$fp) {
  455.                 return $this->raiseError('channel-add: cannot open "' . $params[0] . '"');
  456.             }
  457.             $contents = '';
  458.             while (!feof($fp)) {
  459.                 $contents .= fread($fp, 1024);
  460.             }
  461.             fclose($fp);
  462.         }
  463.         if (!class_exists('PEAR_ChannelFile')) {
  464.             require_once 'PEAR/ChannelFile.php';
  465.         }
  466.         $channel = new PEAR_ChannelFile;
  467.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  468.         $result = $channel->fromXmlString($contents);
  469.         PEAR::staticPopErrorHandling();
  470.         if (!$result) {
  471.             $exit = false;
  472.             if (count($errors = $channel->getErrors(true))) {
  473.                 foreach ($errors as $error) {
  474.                     $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
  475.                     if (!$exit) {
  476.                         $exit = $error['level'] == 'error' ? true : false;
  477.                     }
  478.                 }
  479.                 if ($exit) {
  480.                     return $this->raiseError('channel-add: invalid channel.xml file');
  481.                 }
  482.             }
  483.         }
  484.         $reg = &$this->config->getRegistry();
  485.         if ($reg->channelExists($channel->getName())) {
  486.             return $this->raiseError('channel-add: Channel "' . $channel->getName() .
  487.                 '" exists, use channel-update to update entry');
  488.         }
  489.         $ret = $reg->addChannel($channel, $lastmodified);
  490.         if (PEAR::isError($ret)) {
  491.             return $ret;
  492.         }
  493.         if (!$ret) {
  494.             return $this->raiseError('channel-add: adding Channel "' . $channel->getName() .
  495.                 '" to registry failed');
  496.         }
  497.         $this->config->setChannels($reg->listChannels());
  498.         $this->config->writeConfigFile();
  499.         $this->ui->outputData('Adding Channel "' . $channel->getName() . '" succeeded', $command);
  500.     }
  501.  
  502.     function doUpdate($command, $options, $params)
  503.     {
  504.         $tmpdir = $this->config->get('temp_dir');
  505.         if (!file_exists($tmpdir)) {
  506.             require_once 'System.php';
  507.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  508.             $err = System::mkdir(array('-p', $tmpdir));
  509.             PEAR::staticPopErrorHandling();
  510.             if (PEAR::isError($err)) {
  511.                 return $this->raiseError('channel-add: temp_dir does not exist: "' .
  512.                     $tmpdir . 
  513.                     '" - You can change this location with "pear config-set temp_dir"');
  514.             }
  515.         }
  516.         if (!is_writable($tmpdir)) {
  517.             return $this->raiseError('channel-add: temp_dir is not writable: "' .
  518.                 $tmpdir . 
  519.                 '" - You can change this location with "pear config-set temp_dir"');
  520.         }
  521.         $reg = &$this->config->getRegistry();
  522.         if (sizeof($params) != 1) {
  523.             return $this->raiseError("No channel file specified");
  524.         }
  525.         $lastmodified = false;
  526.         if ((!file_exists($params[0]) || is_dir($params[0]))
  527.               && $reg->channelExists(strtolower($params[0]))) {
  528.             $c = $reg->getChannel(strtolower($params[0]));
  529.             if (PEAR::isError($c)) {
  530.                 return $this->raiseError($c);
  531.             }
  532.             $this->ui->outputData("Updating channel \"$params[0]\"", $command);
  533.             $dl = &$this->getDownloader(array());
  534.             // if force is specified, use a timestamp of "1" to force retrieval
  535.             $lastmodified = isset($options['force']) ? false : $c->lastModified();
  536.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  537.             $contents = $dl->downloadHttp('http://' . $c->getName() . '/channel.xml',
  538.                 $this->ui, $tmpdir, null, $lastmodified);
  539.             PEAR::staticPopErrorHandling();
  540.             if (PEAR::isError($contents)) {
  541.                 return $this->raiseError('Cannot retrieve channel.xml for channel "' .
  542.                     $c->getName() . '" (' . $contents->getMessage() . ')');
  543.             }
  544.             list($contents, $lastmodified) = $contents;
  545.             if (!$contents) {
  546.                 $this->ui->outputData("Channel \"$params[0]\" is up to date");
  547.                 return;
  548.             }
  549.             $contents = implode('', file($contents));
  550.             if (!class_exists('PEAR_ChannelFile')) {
  551.                 require_once 'PEAR/ChannelFile.php';
  552.             }
  553.             $channel = new PEAR_ChannelFile;
  554.             $channel->fromXmlString($contents);
  555.             if (!$channel->getErrors()) {
  556.                 // security check: is the downloaded file for the channel we got it from?
  557.                 if (strtolower($channel->getName()) != strtolower($c->getName())) {
  558.                     if (isset($options['force'])) {
  559.                         $this->ui->log(0, 'WARNING: downloaded channel definition file' .
  560.                             ' for channel "' . $channel->getName() . '" from channel "' .
  561.                             strtolower($c->getName()) . '"');
  562.                     } else {
  563.                         return $this->raiseError('ERROR: downloaded channel definition file' .
  564.                             ' for channel "' . $channel->getName() . '" from channel "' .
  565.                             strtolower($c->getName()) . '"');
  566.                     }
  567.                 }
  568.             }
  569.         } else {
  570.             if (strpos($params[0], '://')) {
  571.                 $dl = &$this->getDownloader();
  572.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  573.                 $loc = $dl->downloadHttp($params[0],
  574.                     $this->ui, $tmpdir, null, $lastmodified);
  575.                 PEAR::staticPopErrorHandling();
  576.                 if (PEAR::isError($loc)) {
  577.                     return $this->raiseError("Cannot open " . $params[0] .
  578.                          ' (' . $loc->getMessage() . ')');
  579.                 } else {
  580.                     list($loc, $lastmodified) = $loc;
  581.                     $contents = implode('', file($loc));
  582.                 }
  583.             } else {
  584.                 $fp = false;
  585.                 if (file_exists($params[0])) {
  586.                     $fp = fopen($params[0], 'r');
  587.                 }
  588.                 if (!$fp) {
  589.                     return $this->raiseError("Cannot open " . $params[0]);
  590.                 }
  591.                 $contents = '';
  592.                 while (!feof($fp)) {
  593.                     $contents .= fread($fp, 1024);
  594.                 }
  595.                 fclose($fp);
  596.             }
  597.             if (!class_exists('PEAR_ChannelFile')) {
  598.                 require_once 'PEAR/ChannelFile.php';
  599.             }
  600.             $channel = new PEAR_ChannelFile;
  601.             $channel->fromXmlString($contents);
  602.         }
  603.         $exit = false;
  604.         if (count($errors = $channel->getErrors(true))) {
  605.             foreach ($errors as $error) {
  606.                 $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
  607.                 if (!$exit) {
  608.                     $exit = $error['level'] == 'error' ? true : false;
  609.                 }
  610.             }
  611.             if ($exit) {
  612.                 return $this->raiseError('Invalid channel.xml file');
  613.             }
  614.         }
  615.         if (!$reg->channelExists($channel->getName())) {
  616.             return $this->raiseError('Error: Channel "' . $channel->getName() .
  617.                 '" does not exist, use channel-add to add an entry');
  618.         }
  619.         $ret = $reg->updateChannel($channel, $lastmodified);
  620.         if (PEAR::isError($ret)) {
  621.             return $ret;
  622.         }
  623.         if (!$ret) {
  624.             return $this->raiseError('Updating Channel "' . $channel->getName() .
  625.                 '" in registry failed');
  626.         }
  627.         $this->config->setChannels($reg->listChannels());
  628.         $this->config->writeConfigFile();
  629.         $this->ui->outputData('Update of Channel "' . $channel->getName() . '" succeeded');
  630.     }
  631.  
  632.     function &getDownloader()
  633.     {
  634.         if (!class_exists('PEAR_Downloader')) {
  635.             require_once 'PEAR/Downloader.php';
  636.         }
  637.         $a = new PEAR_Downloader($this->ui, array(), $this->config);
  638.         return $a;
  639.     }
  640.  
  641.     function doAlias($command, $options, $params)
  642.     {
  643.         $reg = &$this->config->getRegistry();
  644.         if (sizeof($params) == 1) {
  645.             return $this->raiseError('No channel alias specified');
  646.         }
  647.         if (sizeof($params) != 2) {
  648.             return $this->raiseError(
  649.                 'Invalid format, correct is: channel-alias channel alias');
  650.         }
  651.         if (!$reg->channelExists($params[0], true)) {
  652.             if ($reg->isAlias($params[0])) {
  653.                 $extra = ' (use "channel-alias ' . $reg->channelName($params[0]) . ' ' .
  654.                     strtolower($params[1]) . '")';
  655.             } else {
  656.                 $extra = '';
  657.             }
  658.             return $this->raiseError('"' . $params[0] . '" is not a valid channel' . $extra);
  659.         }
  660.         if ($reg->isAlias($params[1])) {
  661.             return $this->raiseError('Channel "' . $reg->channelName($params[1]) . '" is ' .
  662.                 'already aliased to "' . strtolower($params[1]) . '", cannot re-alias');
  663.         }
  664.         $chan = &$reg->getChannel($params[0]);
  665.         if (PEAR::isError($chan)) {
  666.             return $this->raiseError('Corrupt registry?  Error retrieving channel "' . $params[0] .
  667.                 '" information (' . $chan->getMessage() . ')');
  668.         }
  669.         // make it a local alias
  670.         if (!$chan->setAlias(strtolower($params[1]), true)) {
  671.             return $this->raiseError('Alias "' . strtolower($params[1]) .
  672.                 '" is not a valid channel alias');
  673.         }
  674.         $reg->updateChannel($chan);
  675.         $this->ui->outputData('Channel "' . $chan->getName() . '" aliased successfully to "' .
  676.             strtolower($params[1]) . '"');
  677.     }
  678.  
  679.     /**
  680.      * The channel-discover command
  681.      *
  682.      * @param string $command command name
  683.      * @param array  $options option_name => value
  684.      * @param array  $params  list of additional parameters.
  685.      *               $params[0] should contain a string with either:
  686.      *               - <channel name> or
  687.      *               - <username>:<password>@<channel name>
  688.      * @return null|PEAR_Error
  689.      */
  690.     function doDiscover($command, $options, $params)
  691.     {
  692.         $reg = &$this->config->getRegistry();
  693.         if (sizeof($params) != 1) {
  694.             return $this->raiseError("No channel server specified");
  695.         }
  696.         
  697.         // Look for the possible input format "<username>:<password>@<channel>"
  698.         if (preg_match('/^(.+):(.+)@(.+)\\z/', $params[0], $matches)) {
  699.             $username = $matches[1];
  700.             $password = $matches[2];
  701.             $channel = $matches[3];
  702.         } else {
  703.             $channel = $params[0];
  704.         }
  705.         
  706.         if ($reg->channelExists($channel)) {
  707.             if ($reg->isAlias($channel)) {
  708.                 return $this->raiseError("A channel alias named \"$channel\" " .
  709.                     'already exists, aliasing channel "' . $reg->channelName($channel)
  710.                     . '"');
  711.             } else {
  712.                 return $this->raiseError("Channel \"$channel\" is already initialized");
  713.             }
  714.         }
  715.         $this->pushErrorHandling(PEAR_ERROR_RETURN);
  716.         $err = $this->doAdd($command, $options, array('http://' . $channel . '/channel.xml'));
  717.         $this->popErrorHandling();
  718.         if (PEAR::isError($err)) {
  719.             return $this->raiseError("Discovery of channel \"$channel\" failed (" .
  720.                 $err->getMessage() . ')');
  721.         }
  722.         
  723.         // Store username/password if they were given
  724.         // Arguably we should do a logintest on the channel here, but since
  725.         // that's awkward on a REST-based channel (even "pear login" doesn't
  726.         // do it for those), and XML-RPC is deprecated, it's fairly pointless.
  727.         if (isset($username)) {
  728.             $this->config->set('username', $username, 'user', $channel);
  729.             $this->config->set('password', $password, 'user', $channel);
  730.             $this->config->store();
  731.             $this->ui->outputData("Stored login for channel \"$channel\" using username \"$username\"", $command);
  732.         }
  733.         
  734.         $this->ui->outputData("Discovery of channel \"$channel\" succeeded", $command);
  735.     }
  736. }
  737. ?>
  738.