PageRenderTime 55ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/php/PEAR/Command/Channels.php

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