source: branches/version-2_13-dev/data/module/PEAR/Command/Channels.php @ 23125

Revision 23125, 32.7 KB checked in by kimoto, 11 years ago (diff)

#2275 PEAR更新
不要なrequire_onceの削除
レガシーなPEARモジュールは使わない
SearchReplace?.phpのパスが間違っているので修正

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