Mage_Downloader - Version 1.6.1.0

Version Notes

1.6.1.0

Download this release

Release Info

Developer Magento Core Team
Extension Mage_Downloader
Version 1.6.1.0
Comparing to
See all releases


Version 1.6.1.0

Files changed (136) hide show
  1. .htaccess +186 -0
  2. downloader/.htaccess +11 -0
  3. downloader/Maged/Connect.php +467 -0
  4. downloader/Maged/Connect/Frontend.php +149 -0
  5. downloader/Maged/Controller.php +977 -0
  6. downloader/Maged/Exception.php +37 -0
  7. downloader/Maged/Model.php +99 -0
  8. downloader/Maged/Model/Config.php +84 -0
  9. downloader/Maged/Model/Config/Abstract.php +134 -0
  10. downloader/Maged/Model/Config/Community.php +112 -0
  11. downloader/Maged/Model/Config/Interface.php +90 -0
  12. downloader/Maged/Model/Connect.php +491 -0
  13. downloader/Maged/Model/Connect/Request.php +43 -0
  14. downloader/Maged/Model/Dowloader.php +30 -0
  15. downloader/Maged/Model/Session.php +224 -0
  16. downloader/Maged/View.php +155 -0
  17. downloader/config.ini +1 -0
  18. downloader/index.php +36 -0
  19. downloader/js/prototype.js +3277 -0
  20. downloader/lib/Mage/Archive.php +222 -0
  21. downloader/lib/Mage/Archive/Abstract.php +84 -0
  22. downloader/lib/Mage/Archive/Bz.php +79 -0
  23. downloader/lib/Mage/Archive/Gz.php +77 -0
  24. downloader/lib/Mage/Archive/Interface.php +53 -0
  25. downloader/lib/Mage/Archive/Tar.php +372 -0
  26. downloader/lib/Mage/Autoload/Simple.php +52 -0
  27. downloader/lib/Mage/Connect/Channel/Generator.php +63 -0
  28. downloader/lib/Mage/Connect/Channel/Parser.php +25 -0
  29. downloader/lib/Mage/Connect/Channel/VO.php +113 -0
  30. downloader/lib/Mage/Connect/Command.php +390 -0
  31. downloader/lib/Mage/Connect/Command/Channels.php +189 -0
  32. downloader/lib/Mage/Connect/Command/Channels_Header.php +104 -0
  33. downloader/lib/Mage/Connect/Command/Config.php +213 -0
  34. downloader/lib/Mage/Connect/Command/Config_Header.php +100 -0
  35. downloader/lib/Mage/Connect/Command/Install.php +567 -0
  36. downloader/lib/Mage/Connect/Command/Install_Header.php +237 -0
  37. downloader/lib/Mage/Connect/Command/Package.php +204 -0
  38. downloader/lib/Mage/Connect/Command/Package_Header.php +76 -0
  39. downloader/lib/Mage/Connect/Command/Registry.php +364 -0
  40. downloader/lib/Mage/Connect/Command/Registry_Header.php +84 -0
  41. downloader/lib/Mage/Connect/Command/Remote.php +231 -0
  42. downloader/lib/Mage/Connect/Command/Remote_Header.php +88 -0
  43. downloader/lib/Mage/Connect/Config.php +464 -0
  44. downloader/lib/Mage/Connect/Converter.php +336 -0
  45. downloader/lib/Mage/Connect/Frontend.php +251 -0
  46. downloader/lib/Mage/Connect/Frontend/CLI.php +456 -0
  47. downloader/lib/Mage/Connect/Ftp.php +523 -0
  48. downloader/lib/Mage/Connect/Loader.php +51 -0
  49. downloader/lib/Mage/Connect/Loader/Ftp.php +155 -0
  50. downloader/lib/Mage/Connect/Package.php +1499 -0
  51. downloader/lib/Mage/Connect/Package/Extension.php +1 -0
  52. downloader/lib/Mage/Connect/Package/Hotfix.php +137 -0
  53. downloader/lib/Mage/Connect/Package/Maintainer.php +1 -0
  54. downloader/lib/Mage/Connect/Package/Reader.php +150 -0
  55. downloader/lib/Mage/Connect/Package/Target.php +126 -0
  56. downloader/lib/Mage/Connect/Package/VO.php +96 -0
  57. downloader/lib/Mage/Connect/Package/Writer.php +177 -0
  58. downloader/lib/Mage/Connect/Packager.php +909 -0
  59. downloader/lib/Mage/Connect/Repository.php +1 -0
  60. downloader/lib/Mage/Connect/Repository/Abstract.php +1 -0
  61. downloader/lib/Mage/Connect/Repository/Channel.php +1 -0
  62. downloader/lib/Mage/Connect/Repository/Channel/Abstract.php +1 -0
  63. downloader/lib/Mage/Connect/Repository/Channel/Commercial.php +1 -0
  64. downloader/lib/Mage/Connect/Repository/Channel/Community.php +1 -0
  65. downloader/lib/Mage/Connect/Repository/Channel/Core.php +1 -0
  66. downloader/lib/Mage/Connect/Repository/Local.php +1 -0
  67. downloader/lib/Mage/Connect/Rest.php +366 -0
  68. downloader/lib/Mage/Connect/Singleconfig.php +934 -0
  69. downloader/lib/Mage/Connect/Structures/Graph.php +248 -0
  70. downloader/lib/Mage/Connect/Structures/Node.php +257 -0
  71. downloader/lib/Mage/Connect/Validator.php +440 -0
  72. downloader/lib/Mage/DB/Exception.php +36 -0
  73. downloader/lib/Mage/DB/Mysqli.php +532 -0
  74. downloader/lib/Mage/Exception.php +35 -0
  75. downloader/lib/Mage/HTTP/Client.php +84 -0
  76. downloader/lib/Mage/HTTP/Client/Curl.php +556 -0
  77. downloader/lib/Mage/HTTP/Client/Socket.php +537 -0
  78. downloader/lib/Mage/HTTP/IClient.php +145 -0
  79. downloader/lib/Mage/System/Args.php +102 -0
  80. downloader/lib/Mage/System/Dirs.php +104 -0
  81. downloader/lib/Mage/Xml/Generator.php +114 -0
  82. downloader/lib/Mage/Xml/Parser.php +115 -0
  83. downloader/mage.php +156 -0
  84. downloader/skin/boxes.css +217 -0
  85. downloader/skin/ie7boxes.css +27 -0
  86. downloader/skin/ieboxes.css +29 -0
  87. downloader/skin/images/Magento_Connect.jpg +0 -0
  88. downloader/skin/images/ajax-loader-tr.gif +0 -0
  89. downloader/skin/images/btn_bg.gif +0 -0
  90. downloader/skin/images/header_bg.gif +0 -0
  91. downloader/skin/images/logo.gif +0 -0
  92. downloader/skin/images/nav_bg.gif +0 -0
  93. downloader/skin/images/nav_separator.gif +0 -0
  94. downloader/skin/install/boxes.css +414 -0
  95. downloader/skin/install/clears.css +70 -0
  96. downloader/skin/install/ie7minus.css +40 -0
  97. downloader/skin/install/iestyles.css +78 -0
  98. downloader/skin/install/images/error_msg_icon.gif +0 -0
  99. downloader/skin/install/images/footer_bg.gif +0 -0
  100. downloader/skin/install/images/footer_container_bg.gif +0 -0
  101. downloader/skin/install/images/footer_info_separator.gif +0 -0
  102. downloader/skin/install/images/footer_informational_bg.gif +0 -0
  103. downloader/skin/install/images/footer_left.gif +0 -0
  104. downloader/skin/install/images/footer_legality_bg.gif +0 -0
  105. downloader/skin/install/images/footer_right.gif +0 -0
  106. downloader/skin/install/images/header_bg.gif +0 -0
  107. downloader/skin/install/images/header_nav_bg.gif +0 -0
  108. downloader/skin/install/images/header_top_bg.jpg +0 -0
  109. downloader/skin/install/images/header_top_container_bg.jpg +0 -0
  110. downloader/skin/install/images/logo.gif +0 -0
  111. downloader/skin/install/images/main_bg.gif +0 -0
  112. downloader/skin/install/images/main_container_bg.gif +0 -0
  113. downloader/skin/install/images/note_msg_icon.gif +0 -0
  114. downloader/skin/install/images/success_msg_icon.gif +0 -0
  115. downloader/skin/install/images/validation_advice_bg.gif +0 -0
  116. downloader/skin/install/reset.css +83 -0
  117. downloader/template/.htaccess +2 -0
  118. downloader/template/connect/iframe.phtml +121 -0
  119. downloader/template/connect/packages.phtml +221 -0
  120. downloader/template/connect/packages_prepare.phtml +78 -0
  121. downloader/template/exception.phtml +36 -0
  122. downloader/template/footer.phtml +40 -0
  123. downloader/template/header.phtml +73 -0
  124. downloader/template/index.phtml +36 -0
  125. downloader/template/install/download.phtml +184 -0
  126. downloader/template/install/footer.phtml +49 -0
  127. downloader/template/install/header.phtml +99 -0
  128. downloader/template/install/writable.phtml +40 -0
  129. downloader/template/login.phtml +43 -0
  130. downloader/template/messages.phtml +39 -0
  131. downloader/template/noroute.phtml +31 -0
  132. downloader/template/settings.phtml +166 -0
  133. downloader/template/writable.phtml +35 -0
  134. index.php +80 -0
  135. mage +54 -0
  136. package.xml +18 -0
.htaccess ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ############################################
2
+ ## uncomment these lines for CGI mode
3
+ ## make sure to specify the correct cgi php binary file name
4
+ ## it might be /cgi-bin/php-cgi
5
+
6
+ # Action php5-cgi /cgi-bin/php5-cgi
7
+ # AddHandler php5-cgi .php
8
+
9
+ ############################################
10
+ ## GoDaddy specific options
11
+
12
+ # Options -MultiViews
13
+
14
+ ## you might also need to add this line to php.ini
15
+ ## cgi.fix_pathinfo = 1
16
+ ## if it still doesn't work, rename php.ini to php5.ini
17
+
18
+ ############################################
19
+ ## this line is specific for 1and1 hosting
20
+
21
+ #AddType x-mapp-php5 .php
22
+ #AddHandler x-mapp-php5 .php
23
+
24
+ ############################################
25
+ ## default index file
26
+
27
+ DirectoryIndex index.php
28
+
29
+ <IfModule mod_php5.c>
30
+
31
+ ############################################
32
+ ## adjust memory limit
33
+
34
+ # php_value memory_limit 64M
35
+ php_value memory_limit 256M
36
+ php_value max_execution_time 18000
37
+
38
+ ############################################
39
+ ## disable magic quotes for php request vars
40
+
41
+ php_flag magic_quotes_gpc off
42
+
43
+ ############################################
44
+ ## disable automatic session start
45
+ ## before autoload was initialized
46
+
47
+ php_flag session.auto_start off
48
+
49
+ ############################################
50
+ ## enable resulting html compression
51
+
52
+ #php_flag zlib.output_compression on
53
+
54
+ ###########################################
55
+ # disable user agent verification to not break multiple image upload
56
+
57
+ php_flag suhosin.session.cryptua off
58
+
59
+ ###########################################
60
+ # turn off compatibility with PHP4 when dealing with objects
61
+
62
+ php_flag zend.ze1_compatibility_mode Off
63
+
64
+ </IfModule>
65
+
66
+ <IfModule mod_security.c>
67
+ ###########################################
68
+ # disable POST processing to not break multiple image upload
69
+
70
+ SecFilterEngine Off
71
+ SecFilterScanPOST Off
72
+ </IfModule>
73
+
74
+ <IfModule mod_deflate.c>
75
+
76
+ ############################################
77
+ ## enable apache served files compression
78
+ ## http://developer.yahoo.com/performance/rules.html#gzip
79
+
80
+ # Insert filter on all content
81
+ ###SetOutputFilter DEFLATE
82
+ # Insert filter on selected content types only
83
+ #AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript
84
+
85
+ # Netscape 4.x has some problems...
86
+ #BrowserMatch ^Mozilla/4 gzip-only-text/html
87
+
88
+ # Netscape 4.06-4.08 have some more problems
89
+ #BrowserMatch ^Mozilla/4\.0[678] no-gzip
90
+
91
+ # MSIE masquerades as Netscape, but it is fine
92
+ #BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
93
+
94
+ # Don't compress images
95
+ #SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
96
+
97
+ # Make sure proxies don't deliver the wrong content
98
+ #Header append Vary User-Agent env=!dont-vary
99
+
100
+ </IfModule>
101
+
102
+ <IfModule mod_ssl.c>
103
+
104
+ ############################################
105
+ ## make HTTPS env vars available for CGI mode
106
+
107
+ SSLOptions StdEnvVars
108
+
109
+ </IfModule>
110
+
111
+ <IfModule mod_rewrite.c>
112
+
113
+ ############################################
114
+ ## enable rewrites
115
+
116
+ Options +FollowSymLinks
117
+ RewriteEngine on
118
+
119
+ ############################################
120
+ ## you can put here your magento root folder
121
+ ## path relative to web root
122
+
123
+ #RewriteBase /magento/
124
+
125
+ ############################################
126
+ ## workaround for HTTP authorization
127
+ ## in CGI environment
128
+
129
+ RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
130
+
131
+ ############################################
132
+ ## always send 404 on missing files in these folders
133
+
134
+ RewriteCond %{REQUEST_URI} !^/(media|skin|js)/
135
+
136
+ ############################################
137
+ ## never rewrite for existing files, directories and links
138
+
139
+ RewriteCond %{REQUEST_FILENAME} !-f
140
+ RewriteCond %{REQUEST_FILENAME} !-d
141
+ RewriteCond %{REQUEST_FILENAME} !-l
142
+
143
+ ############################################
144
+ ## rewrite everything else to index.php
145
+
146
+ RewriteRule .* index.php [L]
147
+
148
+ </IfModule>
149
+
150
+
151
+ ############################################
152
+ ## Prevent character encoding issues from server overrides
153
+ ## If you still have problems, use the second line instead
154
+
155
+ AddDefaultCharset Off
156
+ #AddDefaultCharset UTF-8
157
+
158
+ <IfModule mod_expires.c>
159
+
160
+ ############################################
161
+ ## Add default Expires header
162
+ ## http://developer.yahoo.com/performance/rules.html#expires
163
+
164
+ ExpiresDefault "access plus 1 year"
165
+
166
+ </IfModule>
167
+
168
+ ############################################
169
+ ## By default allow all access
170
+
171
+ Order allow,deny
172
+ Allow from all
173
+
174
+ ###########################################
175
+ ## Deny access to release notes to prevent disclosure of the installed Magento version
176
+
177
+ <Files RELEASE_NOTES.txt>
178
+ order allow,deny
179
+ deny from all
180
+ </Files>
181
+
182
+ ############################################
183
+ ## If running in cluster environment, uncomment this
184
+ ## http://developer.yahoo.com/performance/rules.html#etags
185
+
186
+ #FileETag none
downloader/.htaccess ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <IfModule mod_deflate.c>
2
+
3
+ RemoveOutputFilter DEFLATE
4
+ RemoveOutputFilter GZIP
5
+
6
+ </IfModule>
7
+
8
+ <Files ~ "\.(cfg|ini|xml)$">
9
+ order allow,deny
10
+ deny from all
11
+ </Files>
downloader/Maged/Connect.php ADDED
@@ -0,0 +1,467 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ error_reporting(E_ALL & ~E_NOTICE);
28
+
29
+ // just a shortcut
30
+ if (!defined('DS')) {
31
+ define('DS', DIRECTORY_SEPARATOR);
32
+ }
33
+
34
+ // add Mage lib in include_path if needed
35
+ $_includePath = get_include_path();
36
+ $_libDir = dirname(dirname(__FILE__)) . DS . 'lib';
37
+ if (strpos($_includePath, $_libDir) === false) {
38
+ if (substr($_includePath, 0, 2) === '.' . PATH_SEPARATOR) {
39
+ $_includePath = '.' . PATH_SEPARATOR . $_libDir . PATH_SEPARATOR . substr($_includePath, 2);
40
+ } else {
41
+ $_includePath = $_libDir . PATH_SEPARATOR . $_includePath;
42
+ }
43
+ set_include_path($_includePath);
44
+ }
45
+
46
+ /**
47
+ * Class for connect
48
+ *
49
+ * @category Mage
50
+ * @package Mage_Connect
51
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
52
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
53
+ */
54
+ class Maged_Connect
55
+ {
56
+
57
+ /**
58
+ * Object of config
59
+ *
60
+ * @var Mage_Connect_Config
61
+ */
62
+ protected $_config;
63
+
64
+ /**
65
+ * Object of single config
66
+ *
67
+ * @var Mage_Connect_Singleconfig
68
+ */
69
+ protected $_sconfig;
70
+
71
+ /**
72
+ * Object of frontend
73
+ *
74
+ * @var Mage_Connect_Frontend
75
+ */
76
+ protected $_frontend;
77
+
78
+ /**
79
+ * Internal cache for command objects
80
+ *
81
+ * @var array
82
+ */
83
+ protected $_cmdCache = array();
84
+
85
+ /**
86
+ * Instance of class
87
+ *
88
+ * @var Maged_Connect
89
+ */
90
+ static protected $_instance;
91
+
92
+ /**
93
+ * Constructor
94
+ */
95
+ public function __construct()
96
+ {
97
+ $this->getConfig();
98
+ $this->getSingleConfig();
99
+ $this->getFrontend();
100
+ }
101
+
102
+ /**
103
+ * Initialize instance
104
+ *
105
+ * @return Maged_Connect
106
+ */
107
+ public static function getInstance()
108
+ {
109
+ if (!self::$_instance) {
110
+ self::$_instance = new self;
111
+ }
112
+ return self::$_instance;
113
+ }
114
+
115
+ /**
116
+ * Retrieve object of config and set it to Mage_Connect_Command
117
+ *
118
+ * @return Mage_Connect_Config
119
+ */
120
+ public function getConfig()
121
+ {
122
+ if (!$this->_config) {
123
+ $this->_config = new Mage_Connect_Config();
124
+ $ftp=$this->_config->__get('remote_config');
125
+ if(!empty($ftp)){
126
+ $packager = new Mage_Connect_Packager();
127
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
128
+ $this->_config=$config;
129
+ $this->_sconfig=$cache;
130
+ }
131
+ $this->_config->magento_root = dirname(dirname(__FILE__)).DS.'..';
132
+ Mage_Connect_Command::setConfigObject($this->_config);
133
+ }
134
+ return $this->_config;
135
+ }
136
+
137
+ /**
138
+ * Retrieve object of single config and set it to Mage_Connect_Command
139
+ *
140
+ * @param bool $reload
141
+ * @return Mage_Connect_Singleconfig
142
+ */
143
+ public function getSingleConfig($reload = false)
144
+ {
145
+ if(!$this->_sconfig || $reload) {
146
+ $this->_sconfig = new Mage_Connect_Singleconfig($this->getConfig()->magento_root . DIRECTORY_SEPARATOR . $this->getConfig()->downloader_path . DIRECTORY_SEPARATOR . Mage_Connect_Singleconfig::DEFAULT_SCONFIG_FILENAME);
147
+ }
148
+ Mage_Connect_Command::setSconfig($this->_sconfig);
149
+ return $this->_sconfig;
150
+
151
+ }
152
+
153
+ /**
154
+ * Retrieve object of frontend and set it to Mage_Connect_Command
155
+ *
156
+ * @return Maged_Connect_Frontend
157
+ */
158
+ public function getFrontend()
159
+ {
160
+ if (!$this->_frontend) {
161
+ $this->_frontend = new Maged_Connect_Frontend();
162
+ Mage_Connect_Command::setFrontendObject($this->_frontend);
163
+ }
164
+ return $this->_frontend;
165
+ }
166
+
167
+ /**
168
+ * Retrieve lof from frontend
169
+ *
170
+ * @return array
171
+ */
172
+ public function getLog()
173
+ {
174
+ return $this->getFrontend()->getLog();
175
+ }
176
+
177
+ /**
178
+ * Retrieve output from frontend
179
+ *
180
+ * @return array
181
+ */
182
+ public function getOutput()
183
+ {
184
+ return $this->getFrontend()->getOutput();
185
+ }
186
+
187
+ /**
188
+ * Clean registry
189
+ *
190
+ * @return Maged_Connect
191
+ */
192
+ public function cleanSconfig()
193
+ {
194
+ $this->getSingleConfig()->clear();
195
+ return $this;
196
+ }
197
+
198
+ /**
199
+ * Delete directory recursively
200
+ *
201
+ * @param string $path
202
+ * @return Maged_Connect
203
+ */
204
+ public function delTree($path) {
205
+ if (@is_dir($path)) {
206
+ $entries = @scandir($path);
207
+ foreach ($entries as $entry) {
208
+ if ($entry != '.' && $entry != '..') {
209
+ $this->delTree($path.DS.$entry);
210
+ }
211
+ }
212
+ @rmdir($path);
213
+ } else {
214
+ @unlink($path);
215
+ }
216
+ return $this;
217
+ }
218
+
219
+ /**
220
+ * Run commands from Mage_Connect_Command
221
+ *
222
+ * @param string $command
223
+ * @param array $options
224
+ * @param array $params
225
+ * @return
226
+ */
227
+ public function run($command, $options=array(), $params=array())
228
+ {
229
+ @set_time_limit(0);
230
+ @ini_set('memory_limit', '256M');
231
+
232
+ if (empty($this->_cmdCache[$command])) {
233
+ Mage_Connect_Command::getCommands();
234
+ /**
235
+ * @var $cmd Mage_Connect_Command
236
+ */
237
+ $cmd = Mage_Connect_Command::getInstance($command);
238
+ if ($cmd instanceof Mage_Connect_Error) {
239
+ return $cmd;
240
+ }
241
+ $this->_cmdCache[$command] = $cmd;
242
+ } else {
243
+ /**
244
+ * @var $cmd Mage_Connect_Command
245
+ */
246
+ $cmd = $this->_cmdCache[$command];
247
+ }
248
+ $ftp=$this->getConfig()->remote_config;
249
+ if(strlen($ftp)>0){
250
+ $options=array_merge($options, array('ftp'=>$ftp));
251
+ }
252
+ $cmd->run($command, $options, $params);
253
+ if ($cmd->ui()->hasErrors()) {
254
+ return false;
255
+ } else {
256
+ return true;
257
+ }
258
+ }
259
+
260
+ public function setRemoteConfig($uri) #$host, $user, $password, $path='', $port=null)
261
+ {
262
+ #$uri = 'ftp://' . $user . ':' . $password . '@' . $host . (is_numeric($port) ? ':' . $port : '') . '/' . trim($path, '/') . '/';
263
+ //$this->run('config-set', array(), array('remote_config', $uri));
264
+ //$this->run('config-set', array('ftp'=>$uri), array('remote_config', $uri));
265
+ $this->getConfig()->remote_config=$uri;
266
+ return $this;
267
+ }
268
+
269
+ /**
270
+ *
271
+ * @param array $errors Error messages
272
+ * @return Maged_Connect
273
+ */
274
+ public function showConnectErrors($errors)
275
+ {
276
+ echo '<script type="text/javascript">';
277
+ $run = new Maged_Model_Connect_Request();
278
+ if ($callback = $run->get('failure_callback')) {
279
+ if (is_array($callback)) {
280
+ call_user_func_array($callback, array($result));
281
+ } else {
282
+ echo $callback;
283
+ }
284
+ }
285
+ echo '</script>';
286
+
287
+ return $this;
288
+ }
289
+
290
+ /**
291
+ * Run Mage_Connect_Command with html output console style
292
+ *
293
+ * @param array|Maged_Model $runParams command, options, params,
294
+ * comment, success_callback, failure_callback
295
+ */
296
+ public function runHtmlConsole($runParams)
297
+ {
298
+ if (function_exists('apache_setenv')) {
299
+ apache_setenv('no-gzip', '1');
300
+ }
301
+ @ini_set('zlib.output_compression', 0);
302
+ @ini_set('implicit_flush', 1);
303
+ for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
304
+ ob_implicit_flush();
305
+
306
+ $fe = $this->getFrontend();
307
+ $oldLogStream = $fe->getLogStream();
308
+ $fe->setLogStream('stdout');
309
+
310
+ if ($runParams instanceof Maged_Model) {
311
+ $run = $runParams;
312
+ } elseif (is_array($runParams)) {
313
+ $run = new Maged_Model_Connect_Request($runParams);
314
+ } elseif (is_string($runParams)) {
315
+ $run = new Maged_Model_Connect_Request(array('comment'=>$runParams));
316
+ } else {
317
+ throw Maged_Exception("Invalid run parameters");
318
+ }
319
+
320
+ if (!$run->get('no-header')) {
321
+ ?>
322
+ <html><head><style type="text/css">
323
+ body { margin:0px;
324
+ padding:3px;
325
+ background:black;
326
+ color:#2EC029;
327
+ font:normal 11px Lucida Console, Courier New, serif;
328
+ }
329
+ </style></head><body>
330
+ <script type="text/javascript">
331
+ if (parent && parent.disableInputs) {
332
+ parent.disableInputs(true);
333
+ }
334
+ if (typeof auto_scroll=='undefined') {
335
+ var auto_scroll = window.setInterval(console_scroll, 10);
336
+ }
337
+ function console_scroll()
338
+ {
339
+ if (typeof top.$ != 'function') {
340
+ return;
341
+ }
342
+ if (top.$('connect_iframe_scroll').checked) {
343
+ document.body.scrollTop+=3;
344
+ }
345
+ }
346
+ function show_message(message, newline)
347
+ {
348
+ var bodyElement = document.getElementsByTagName('body')[0];
349
+ if (typeof newline == 'undefined') {
350
+ newline = true
351
+ }
352
+ if (newline) {
353
+ bodyElement.innerHTML += '<br/>';
354
+ }
355
+ bodyElement.innerHTML += message;
356
+ }
357
+ function clear_cache(callbacks)
358
+ {
359
+ if (typeof top.Ajax != 'object') {
360
+ return;
361
+ }
362
+ var message = 'Exception during cache and session cleaning';
363
+ var url = window.location.href.split('?')[0] + '?A=cleanCache';
364
+ var intervalID = setInterval(function() {show_message('.', false); }, 500);
365
+ var clean = 0;
366
+ var maintenance = 0;
367
+ if (window.location.href.indexOf('clean_sessions') >= 0) {
368
+ clean = 1;
369
+ }
370
+ if (window.location.href.indexOf('maintenance') >= 0) {
371
+ maintenance = 1;
372
+ }
373
+
374
+ new top.Ajax.Request(url, {
375
+ method: 'post',
376
+ parameters: {clean_sessions:clean, maintenance:maintenance},
377
+ onCreate: function() {
378
+ show_message('Cleaning cache');
379
+ show_message('');
380
+ },
381
+ onSuccess: function(transport, json) {
382
+ var result = true;
383
+ try{
384
+ var response = eval('(' + transport.responseText + ')');
385
+ if (typeof response.result != 'undefined') {
386
+ result = response.result;
387
+ } else {
388
+ result = false;
389
+ }
390
+ if (typeof response.message != 'undefined') {
391
+ if (response.message.length > 0) {
392
+ message = response.message;
393
+ } else {
394
+ message = 'Cache cleaned successfully';
395
+ }
396
+ }
397
+ } catch (ex){
398
+ result = false;
399
+ }
400
+ if (result) {
401
+ callbacks.success();
402
+ } else {
403
+ callbacks.fail();
404
+ }
405
+ },
406
+ onFailure: function() {
407
+ callbacks.fail();
408
+ },
409
+ onComplete: function(transport) {
410
+ clearInterval(intervalID);
411
+ show_message(message);
412
+ }
413
+ });
414
+ }
415
+ </script>
416
+ <?php
417
+ }
418
+ echo htmlspecialchars($run->get('comment'));
419
+
420
+ if ($command = $run->get('command')) {
421
+ $result = $this->run($command, $run->get('options'), $run->get('params'));
422
+
423
+ if ($this->getFrontend()->hasErrors()) {
424
+ echo "<br/>CONNECT ERROR: ";
425
+ foreach ($this->getFrontend()->getErrors(false) as $error) {
426
+ echo nl2br($error[1]);
427
+ echo '<br/>';
428
+ }
429
+ }
430
+ echo '<script type="text/javascript">';
431
+ if ($this->getFrontend()->hasErrors()) {
432
+ if ($callback = $run->get('failure_callback')) {
433
+ if (is_array($callback)) {
434
+ call_user_func_array($callback, array($result));
435
+ } else {
436
+ echo $callback;
437
+ }
438
+ }
439
+ } else {
440
+ if (!$run->get('no-footer')) {
441
+ if ($callback = $run->get('success_callback')) {
442
+ if (is_array($callback)) {
443
+ call_user_func_array($callback, array($result));
444
+ } else {
445
+ echo $callback;
446
+ }
447
+ }
448
+ }
449
+ }
450
+ echo '</script>';
451
+ } else {
452
+ $result = false;
453
+ }
454
+ if ($this->getFrontend()->getErrors() || !$run->get('no-footer')) {
455
+ ?>
456
+ <script type="text/javascript">
457
+ if (parent && parent.disableInputs) {
458
+ parent.disableInputs(false);
459
+ }
460
+ </script>
461
+ </body></html>
462
+ <?php
463
+ $fe->setLogStream($oldLogStream);
464
+ }
465
+ return $result;
466
+ }
467
+ }
downloader/Maged/Connect/Frontend.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class frontend
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
33
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
+ */
35
+ class Maged_Connect_Frontend extends Mage_Connect_Frontend
36
+ {
37
+
38
+ /**
39
+ * Log stream or not
40
+ *
41
+ * @var string
42
+ */
43
+ protected $_logStream = null;
44
+
45
+ /**
46
+ * Output cache
47
+ *
48
+ * @var array
49
+ */
50
+ protected $_out = array();
51
+
52
+ /**
53
+ * Set log stream
54
+ *
55
+ * @param string|resource $stream 'stdout' or open php stream
56
+ */
57
+ public function setLogStream($stream)
58
+ {
59
+ $this->_logStream = $stream;
60
+ return $this;
61
+ }
62
+
63
+ /**
64
+ * Retrieve log stream
65
+ *
66
+ * @return string
67
+ */
68
+ public function getLogStream()
69
+ {
70
+ return $this->_logStream;
71
+ }
72
+
73
+ /**
74
+ * Echo data from executed command
75
+ */
76
+ public function output($data)
77
+ {
78
+
79
+ $this->_out = $data;
80
+
81
+ if ('stdout'===$this->_logStream) {
82
+ if (is_string($data)) {
83
+ echo $data."<br/>".str_repeat(" ", 256);
84
+ } elseif (is_array($data)) {
85
+ $data = array_pop($data);
86
+ if (!empty($data['message']) && is_string($data['message'])) {
87
+ echo $data['message']."<br/>".str_repeat(" ", 256);
88
+ } elseif (!empty($data['data'])) {
89
+ if (is_string($data['data'])) {
90
+ echo $data['data']."<br/>".str_repeat(" ", 256);
91
+ } else {
92
+ if (isset($data['title'])) {
93
+ echo $data['title']."<br/>".str_repeat(" ", 256);
94
+ }
95
+ if (is_array($data['data'])) {
96
+ foreach ($data['data'] as $row) {
97
+ foreach ($row as $msg) {
98
+ echo "&nbsp;".$msg;
99
+ }
100
+ echo "<br/>".str_repeat(" ", 256);
101
+ }
102
+ } else {
103
+ echo "&nbsp;".$data['data'];
104
+ }
105
+ }
106
+ }
107
+ } else {
108
+ print_r($data);
109
+ }
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Method for ask client about rewrite all files.
115
+ *
116
+ * @param $string
117
+ */
118
+ public function confirm($string)
119
+ {
120
+ $formId = $_POST['form_id'];
121
+ echo <<<SCRIPT
122
+ <script type="text/javascript">
123
+ if (confirm("{$string}")) {
124
+ parent.document.getElementById('ignore_local_modification').value=1;
125
+ parent.onSuccess();
126
+ if (parent && parent.disableInputs) {
127
+ parent.disableInputs(false);
128
+ }
129
+ window.onload = function () {
130
+ parent.document.getElementById('{$formId}').submit();
131
+ parent.document.getElementById('ignore_local_modification').value='';
132
+ }
133
+ }
134
+ </script>
135
+ SCRIPT;
136
+ }
137
+
138
+ /**
139
+ * Retrieve output cache
140
+ *
141
+ * @return array
142
+ */
143
+ public function getOutput()
144
+ {
145
+ return $this->_out;
146
+ }
147
+
148
+ }
149
+
downloader/Maged/Controller.php ADDED
@@ -0,0 +1,977 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class Controller
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
33
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
+ */
35
+ final class Maged_Controller
36
+ {
37
+ /**
38
+ * Request key of action
39
+ */
40
+ const ACTION_KEY = 'A';
41
+
42
+ /**
43
+ * Instance of class
44
+ *
45
+ * @var Maged_Controller
46
+ */
47
+ private static $_instance;
48
+
49
+ /**
50
+ * Current action name
51
+ *
52
+ * @var string
53
+ */
54
+ private $_action;
55
+
56
+ /**
57
+ * Controller is dispathed flag
58
+ *
59
+ * @var bool
60
+ */
61
+ private $_isDispatched = false;
62
+
63
+ /**
64
+ * Redirect to URL
65
+ *
66
+ * @var string
67
+ */
68
+ private $_redirectUrl;
69
+
70
+ /**
71
+ * Downloader dir path
72
+ *
73
+ * @var string
74
+ */
75
+ private $_rootDir;
76
+
77
+ /**
78
+ * Magento root dir path
79
+ *
80
+ * @var string
81
+ */
82
+ private $_mageDir;
83
+
84
+ /**
85
+ * View instance
86
+ *
87
+ * @var Maged_View
88
+ */
89
+ private $_view;
90
+
91
+ /**
92
+ * Connect config instance
93
+ *
94
+ * @var Mage_Connect_Config
95
+ */
96
+ private $_config;
97
+
98
+ /**
99
+ * Config instance
100
+ *
101
+ * @var Maged_Model_Config
102
+ */
103
+ private $_localConfig;
104
+
105
+ /**
106
+ * Session instance
107
+ *
108
+ * @var Maged_Model_Session
109
+ */
110
+ private $_session;
111
+
112
+ /**
113
+ * Root dir is writable flag
114
+ *
115
+ * @var bool
116
+ */
117
+ private $_writable;
118
+
119
+ /**
120
+ * Use maintenance flag
121
+ *
122
+ * @var bool
123
+ */
124
+ protected $_maintenance;
125
+
126
+ /**
127
+ * Maintenance file path
128
+ *
129
+ * @var string
130
+ */
131
+ protected $_maintenanceFile;
132
+
133
+ /**
134
+ * Register array for singletons
135
+ *
136
+ * @var array
137
+ */
138
+ protected $_singletons = array();
139
+
140
+ //////////////////////////// ACTIONS
141
+
142
+
143
+ /**
144
+ * Get ftp string from post data
145
+ *
146
+ * @param array $post post data
147
+ * @return string FTP Url
148
+ */
149
+ private function getFtpPost($post){
150
+ if (empty($post['ftp_host'])) {
151
+ $_POST['ftp'] = '';
152
+ return '';
153
+ }
154
+ $ftp = 'ftp://';
155
+ $post['ftp_proto'] = 'ftp://';
156
+
157
+ if (!empty($post['ftp_path']) && strlen(trim($post['ftp_path'], '\\/')) > 0) {
158
+ $post['ftp_path'] = '/' . trim($post['ftp_path'], '\\/') . '/';
159
+ } else {
160
+ $post['ftp_path'] = '/';
161
+ }
162
+
163
+ $start = stripos($post['ftp_host'],'ftp://');
164
+ if ($start !== false){
165
+ $post['ftp_proto'] = 'ftp://';
166
+ $post['ftp_host'] = substr($post['ftp_host'], $start + 6 - 1);
167
+ }
168
+ $start = stripos($post['ftp_host'],'ftps://');
169
+ if ($start !== false) {
170
+ $post['ftp_proto'] = 'ftps://';
171
+ $post['ftp_host'] = substr($post['ftp_host'], $start + 7 - 1);
172
+ }
173
+
174
+ $post['ftp_host'] = trim($post['ftp_host'], '\\/');
175
+
176
+ if (!empty($post['ftp_login']) && !empty($post['ftp_password'])){
177
+ $ftp = sprintf("%s%s:%s@%s%s",
178
+ $post['ftp_proto'],
179
+ $post['ftp_login'],
180
+ $post['ftp_password'],
181
+ $post['ftp_host'],
182
+ $post['ftp_path']
183
+ );
184
+ } elseif (!empty($post['ftp_login'])) {
185
+ $ftp = sprintf(
186
+ "%s%s@%s%s",
187
+ $post['ftp_proto'],
188
+ $post['ftp_login'],
189
+ $post['ftp_host'],
190
+ $post['ftp_path']
191
+ );
192
+ } else {
193
+ $ftp = $post['ftp_proto'] . $post['ftp_host'] . $post['ftp_path'];
194
+ }
195
+
196
+ $_POST['ftp'] = $ftp;
197
+ return $ftp;
198
+ }
199
+
200
+ /**
201
+ * NoRoute
202
+ */
203
+ public function norouteAction()
204
+ {
205
+ header("HTTP/1.0 404 Invalid Action");
206
+ echo $this->view()->template('noroute.phtml');
207
+ }
208
+
209
+ /**
210
+ * Login
211
+ */
212
+ public function loginAction()
213
+ {
214
+ $this->view()->set('username', !empty($_GET['username']) ? $_GET['username'] : '');
215
+ echo $this->view()->template('login.phtml');
216
+ }
217
+
218
+ /**
219
+ * Logout
220
+ */
221
+ public function logoutAction()
222
+ {
223
+ $this->session()->logout();
224
+ $this->redirect($this->url());
225
+ }
226
+
227
+ /**
228
+ * Index
229
+ */
230
+ public function indexAction()
231
+ {
232
+ $config = $this->config();
233
+ if (!$this->isInstalled()) {
234
+ $this->view()->set('mage_url', dirname(dirname($_SERVER['SCRIPT_NAME'])));
235
+ $this->view()->set(
236
+ 'use_custom_permissions_mode',
237
+ $config->__get('use_custom_permissions_mode')
238
+ ? $config->__get('use_custom_permissions_mode')
239
+ : '0'
240
+ );
241
+ $this->view()->set('mkdir_mode', decoct($config->__get('global_dir_mode')));
242
+ $this->view()->set('chmod_file_mode', decoct($config->__get('global_file_mode')));
243
+ $this->view()->set('protocol', $config->__get('protocol'));
244
+ $this->channelConfig()->setInstallView($config,$this->view());
245
+
246
+ echo $this->view()->template('install/download.phtml');
247
+ } elseif (!$config->sync_pear) {
248
+ $this->model('connect', true)->connect()->run('sync');
249
+ $this->forward('connectPackages');
250
+ } else {
251
+ $this->forward('connectPackages');
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Empty Action
257
+ */
258
+ public function emptyAction()
259
+ {
260
+ $this->model('connect', true)
261
+ ->connect()
262
+ ->runHtmlConsole('Please wait, preparing for updates...');
263
+ }
264
+
265
+ /**
266
+ * Install all magento
267
+ */
268
+ public function connectInstallAllAction()
269
+ {
270
+ $p = &$_POST;
271
+ $this->getFtpPost($p);
272
+ $errors = $this->model('connect', true)->validateConfigPost($p);
273
+ /* todo show errors */
274
+ if ($errors) {
275
+ $message = "CONNECT ERROR: ";
276
+ foreach ($errors as $err) {
277
+ $message .= $err . "\n";
278
+ }
279
+ $this->model('connect', true)->connect()->runHtmlConsole($message);
280
+ $this->model('connect', true)->connect()->showConnectErrors($errors);
281
+ return;
282
+ }
283
+
284
+ if( 1 == $p['inst_protocol']){
285
+ $this->model('connect', true)->connect()->setRemoteConfig($this->getFtpPost($p));
286
+ }
287
+
288
+ $this->channelConfig()->setPostData($this->config(),$p);
289
+
290
+ $chan = $this->config()->__get('root_channel');
291
+ $this->model('connect', true)->saveConfigPost($_POST);
292
+ $this->channelConfig()->setSettingsSession($_POST, $this->session());
293
+ $this->model('connect', true)->installAll(!empty($_GET['force']), $chan);
294
+ $p = null;
295
+ }
296
+
297
+ /**
298
+ * Connect packages
299
+ */
300
+ public function connectPackagesAction()
301
+ {
302
+ $connect = $this->model('connect', true);
303
+
304
+ if (isset($_GET['loggedin'])) {
305
+ $connect->connect()->run('sync');
306
+ }
307
+
308
+ $this->view()->set('connect', $connect);
309
+ $this->view()->set('channel_config', $this->channelConfig());
310
+ $remoteConfig = $this->config()->remote_config;
311
+ if (!$this->isWritable() && empty($remoteConfig)) {
312
+ $this->view()->set('writable_warning', true);
313
+ }
314
+
315
+ echo $this->view()->template('connect/packages.phtml');
316
+ }
317
+
318
+ /**
319
+ * Connect packages POST
320
+ */
321
+ public function connectPackagesPostAction()
322
+ {
323
+ $actions = isset($_POST['actions']) ? $_POST['actions'] : array();
324
+ if (isset($_POST['ignore_local_modification'])) {
325
+ $ignoreLocalModification = $_POST['ignore_local_modification'];
326
+ } else {
327
+ $ignoreLocalModification = '';
328
+ }
329
+ $this->model('connect', true)->applyPackagesActions($actions, $ignoreLocalModification);
330
+ }
331
+
332
+ /**
333
+ * Prepare package to install, get dependency info.
334
+ */
335
+ public function connectPreparePackagePostAction()
336
+ {
337
+ if (!$_POST) {
338
+ echo "INVALID POST DATA";
339
+ return;
340
+ }
341
+ $prepareResult = $this->model('connect', true)->prepareToInstall($_POST['install_package_id']);
342
+
343
+ $packages = isset($prepareResult['data']) ? $prepareResult['data'] : array();
344
+ $errors = isset($prepareResult['errors']) ? $prepareResult['errors'] : array();
345
+
346
+ $this->view()->set('packages', $packages);
347
+ $this->view()->set('errors', $errors);
348
+ $this->view()->set('package_id', $_POST['install_package_id']);
349
+
350
+ echo $this->view()->template('connect/packages_prepare.phtml');
351
+ }
352
+
353
+ /**
354
+ * Install package
355
+ */
356
+ public function connectInstallPackagePostAction()
357
+ {
358
+ if (!$_POST) {
359
+ echo "INVALID POST DATA";
360
+ return;
361
+ }
362
+ $this->model('connect', true)->installPackage($_POST['install_package_id']);
363
+ }
364
+
365
+ /**
366
+ * Install uploaded package
367
+ */
368
+ public function connectInstallPackageUploadAction()
369
+ {
370
+ if (!$_FILES) {
371
+ echo "No file was uploaded";
372
+ return;
373
+ }
374
+
375
+ if(empty($_FILES['file'])) {
376
+ echo "No file was uploaded";
377
+ return;
378
+ }
379
+
380
+ $info =& $_FILES['file'];
381
+
382
+ if(0 !== intval($info['error'])) {
383
+ echo "File upload problem";
384
+ return;
385
+ }
386
+
387
+ $target = $this->_mageDir . DS . "var/" . uniqid() . $info['name'];
388
+ $res = move_uploaded_file($info['tmp_name'], $target);
389
+ if(false === $res) {
390
+ echo "Error moving uploaded file";
391
+ return;
392
+ }
393
+
394
+ $this->model('connect', true)->installUploadedPackage($target);
395
+ @unlink($target);
396
+ }
397
+
398
+ /**
399
+ * Clean cache on ajax request
400
+ */
401
+ public function cleanCacheAction()
402
+ {
403
+ $result = $this->cleanCache();
404
+ echo json_encode($result);
405
+ }
406
+
407
+ /**
408
+ * Settings
409
+ */
410
+ public function settingsAction()
411
+ {
412
+ $config = $this->config();
413
+ $this->view()->set('preferred_state', $config->__get('preferred_state'));
414
+ $this->view()->set('protocol', $config->__get('protocol'));
415
+
416
+ $this->view()->set('use_custom_permissions_mode', $config->__get('use_custom_permissions_mode'));
417
+ $this->view()->set('mkdir_mode', decoct($config->__get('global_dir_mode')));
418
+ $this->view()->set('chmod_file_mode', decoct($config->__get('global_file_mode')));
419
+
420
+ $this->channelConfig()->setSettingsView($this->session(), $this->view());
421
+
422
+ $fs_disabled =! $this->isWritable();
423
+ $ftpParams = $config->__get('remote_config') ? @parse_url($config->__get('remote_config')) : '';
424
+
425
+ $this->view()->set('fs_disabled', $fs_disabled);
426
+ $this->view()->set('deployment_type', ($fs_disabled || !empty($ftpParams) ? 'ftp' : 'fs'));
427
+
428
+ if (!empty($ftpParams)) {
429
+ $this->view()->set('ftp_host', sprintf("%s://%s", $ftpParams['scheme'], $ftpParams['host']));
430
+ $this->view()->set('ftp_login', $ftpParams['user']);
431
+ $this->view()->set('ftp_password', $ftpParams['pass']);
432
+ $this->view()->set('ftp_path', $ftpParams['path']);
433
+ }
434
+ echo $this->view()->template('settings.phtml');
435
+ }
436
+
437
+ /**
438
+ * Settings post
439
+ */
440
+ public function settingsPostAction()
441
+ {
442
+ if ($_POST) {
443
+ $ftp = $this->getFtpPost($_POST);
444
+
445
+ /* clear startup messages */
446
+ $this->config();
447
+ $this->session()->getMessages();
448
+
449
+ $errors = $this->model('connect', true)->validateConfigPost($_POST);
450
+ if ($errors) {
451
+ foreach ($errors as $err) {
452
+ $this->session()->addMessage('error', $err);
453
+ }
454
+ $this->redirect($this->url('settings'));
455
+ return;
456
+ }
457
+ try {
458
+ if ('ftp' == $_POST['deployment_type'] && !empty($_POST['ftp_host'])) {
459
+ $this->model('connect', true)->connect()->setRemoteConfig($ftp);
460
+ } else {
461
+ $this->model('connect', true)->connect()->setRemoteConfig('');
462
+ $_POST['ftp'] = '';
463
+ }
464
+ $this->channelConfig()->setPostData($this->config(), $_POST);
465
+ $this->model('connect', true)->saveConfigPost($_POST);
466
+ $this->channelConfig()->setSettingsSession($_POST, $this->session());
467
+ $this->model('connect', true)->connect()->run('sync');
468
+ } catch (Exception $e) {
469
+ $this->session()->addMessage('error', "Unable to save settings: " . $e->getMessage());
470
+ }
471
+ }
472
+ $this->redirect($this->url('settings'));
473
+ }
474
+
475
+ //////////////////////////// ABSTRACT
476
+
477
+ /**
478
+ * Constructor
479
+ */
480
+ public function __construct()
481
+ {
482
+ $this->_rootDir = dirname(dirname(__FILE__));
483
+ $this->_mageDir = dirname($this->_rootDir);
484
+ }
485
+
486
+ /**
487
+ * Run
488
+ */
489
+ public static function run()
490
+ {
491
+ try {
492
+ self::singleton()->dispatch();
493
+ } catch (Exception $e) {
494
+ echo $e->getMessage();
495
+ //echo self::singleton()->view()->set('exception', $e)->template("exception.phtml");
496
+ }
497
+ }
498
+
499
+ /**
500
+ * Initialize object of class
501
+ *
502
+ * @return Maged_Controller
503
+ */
504
+ public static function singleton()
505
+ {
506
+ if (!self::$_instance) {
507
+ self::$_instance = new self;
508
+
509
+ if (self::$_instance->isDownloaded() && self::$_instance->isInstalled()) {
510
+ Mage::app('', 'store', array('global_ban_use_cache'=>true));
511
+ Mage::getSingleton('adminhtml/url')->turnOffSecretKey();
512
+ }
513
+ }
514
+ return self::$_instance;
515
+ }
516
+
517
+ /**
518
+ * Retrieve Downloader root dir
519
+ *
520
+ * @return string
521
+ */
522
+ public function getRootDir()
523
+ {
524
+ return $this->_rootDir;
525
+ }
526
+
527
+ /**
528
+ * Retrieve Magento root dir
529
+ *
530
+ * @return string
531
+ */
532
+ public function getMageDir()
533
+ {
534
+ return $this->_mageDir;
535
+ }
536
+
537
+ /**
538
+ * Retrieve Mage Class file path
539
+ *
540
+ * @return string
541
+ */
542
+ public function getMageFilename()
543
+ {
544
+ $ds = DIRECTORY_SEPARATOR;
545
+ return $this->getMageDir() . $ds . 'app' . $ds . 'Mage.php';
546
+ }
547
+
548
+ /**
549
+ * Retrieve path for Varien_Profiler
550
+ *
551
+ * @return string
552
+ */
553
+ public function getVarFilename()
554
+ {
555
+ $ds = DIRECTORY_SEPARATOR;
556
+ return $this->getMageDir() . $ds . 'lib' . $ds . 'Varien' . $ds . 'Profiler.php';
557
+ }
558
+
559
+ /**
560
+ * Retrieve downloader file path
561
+ *
562
+ * @param string $name
563
+ * @return string
564
+ */
565
+ public function filepath($name = '')
566
+ {
567
+ $ds = DIRECTORY_SEPARATOR;
568
+ return rtrim($this->getRootDir() . $ds . str_replace('/', $ds, $name), $ds);
569
+ }
570
+
571
+ /**
572
+ * Retrieve object of view
573
+ *
574
+ * @return Maged_View
575
+ */
576
+ public function view()
577
+ {
578
+ if (!$this->_view) {
579
+ $this->_view = new Maged_View;
580
+ }
581
+ return $this->_view;
582
+ }
583
+
584
+ /**
585
+ * Retrieve object of model
586
+ *
587
+ * @param string $model
588
+ * @param boolean $singleton
589
+ * @return Maged_Model
590
+ */
591
+ public function model($model = null, $singleton = false)
592
+ {
593
+ if ($singleton && isset($this->_singletons[$model])) {
594
+ return $this->_singletons[$model];
595
+ }
596
+
597
+ if (is_null($model)) {
598
+ $class = 'Maged_Model';
599
+ } else {
600
+ $class = 'Maged_Model_'.str_replace(' ', '_', ucwords(str_replace('_', ' ', $model)));
601
+ if (!class_exists($class, false)) {
602
+ include_once str_replace('_', DIRECTORY_SEPARATOR, $class).'.php';
603
+ }
604
+ }
605
+
606
+ $object = new $class();
607
+
608
+ if ($singleton) {
609
+ $this->_singletons[$model] = $object;
610
+ }
611
+
612
+ return $object;
613
+ }
614
+
615
+ /**
616
+ * Retrieve object of config
617
+ *
618
+ * @return Mage_Connect_Config
619
+ */
620
+ public function config()
621
+ {
622
+ if (!$this->_config) {
623
+ $this->_config = $this->model('connect', true)->connect()->getConfig();
624
+ if (!$this->_config->isLoaded()) {
625
+ $this->session()->addMessage('error', "Settings has not been loaded. Used default settings");
626
+ if ($this->_config->getError()) {
627
+ $this->session()->addMessage('error', $this->_config->getError());
628
+ }
629
+ }
630
+ }
631
+ return $this->_config;
632
+ }
633
+
634
+ /**
635
+ * Retrieve object of channel config
636
+ *
637
+ * @return Maged_Model_Config_Interface
638
+ */
639
+ public function channelConfig()
640
+ {
641
+ if (!$this->_localConfig) {
642
+ $this->_localConfig = $this->model('config', true)->getChannelConfig();
643
+ }
644
+ return $this->_localConfig;
645
+ }
646
+
647
+ /**
648
+ * Retrieve object of session
649
+ *
650
+ * @return Maged_Model_Session
651
+ */
652
+ public function session()
653
+ {
654
+ if (!$this->_session) {
655
+ $this->_session = $this->model('session')->start();
656
+ }
657
+ return $this->_session;
658
+ }
659
+
660
+ /**
661
+ * Set Controller action
662
+ *
663
+ * @param string $action
664
+ * @return Maged_Controller
665
+ */
666
+ public function setAction($action=null)
667
+ {
668
+ if (is_null($action)) {
669
+ if (!empty($this->_action)) {
670
+ return $this;
671
+ }
672
+ $action = !empty($_GET[self::ACTION_KEY]) ? $_GET[self::ACTION_KEY] : 'index';
673
+ }
674
+ if (empty($action) || !is_string($action) || !method_exists($this, $this->getActionMethod($action))) {
675
+ //$action = 'noroute';
676
+ $action = 'index';
677
+ }
678
+ $this->_action = $action;
679
+ return $this;
680
+ }
681
+
682
+ /**
683
+ * Retrieve Controller action name
684
+ *
685
+ * @return string
686
+ */
687
+ public function getAction()
688
+ {
689
+ return $this->_action;
690
+ }
691
+
692
+ /**
693
+ * Set Redirect to URL
694
+ *
695
+ * @param string $url
696
+ * @param bool $force
697
+ * @return Maged_Controller
698
+ */
699
+ public function redirect($url, $force = false)
700
+ {
701
+ $this->_redirectUrl = $url;
702
+ if ($force) {
703
+ $this->processRedirect();
704
+ }
705
+ return $this;
706
+ }
707
+
708
+ /**
709
+ * Precess redirect
710
+ *
711
+ * @return Maged_Controller
712
+ */
713
+ public function processRedirect()
714
+ {
715
+ if ($this->_redirectUrl) {
716
+ if (headers_sent()) {
717
+ echo '<script type="text/javascript">location.href="' . $this->_redirectUrl . '"</script>';
718
+ exit;
719
+ } else {
720
+ header("Location: " . $this->_redirectUrl);
721
+ exit;
722
+ }
723
+ }
724
+ return $this;
725
+ }
726
+
727
+ /**
728
+ * Forward to action
729
+ *
730
+ * @param string $action
731
+ * @return Maged_Controller
732
+ */
733
+ public function forward($action)
734
+ {
735
+ $this->setAction($action);
736
+ $this->_isDispatched = false;
737
+ return $this;
738
+ }
739
+
740
+ /**
741
+ * Retrieve action method by action name
742
+ *
743
+ * @param string $action
744
+ * @return string
745
+ */
746
+ public function getActionMethod($action = null)
747
+ {
748
+ $method = (!is_null($action) ? $action : $this->_action) . 'Action';
749
+ return $method;
750
+ }
751
+
752
+ /**
753
+ * Generate URL for action
754
+ *
755
+ * @param string $action
756
+ * @param array $params
757
+ */
758
+ public function url($action = '', $params = array())
759
+ {
760
+ $args = array();
761
+ foreach ($params as $k => $v) {
762
+ $args[] = sprintf('%s=%s', rawurlencode($k), rawurlencode($v));
763
+ }
764
+ $args = $args ? join('&', $args) : '';
765
+
766
+ return sprintf('%s?%s=%s%s', $_SERVER['SCRIPT_NAME'], self::ACTION_KEY, rawurlencode($action), $args);
767
+ }
768
+
769
+ /**
770
+ * Dispatch process
771
+ */
772
+ public function dispatch()
773
+ {
774
+ header('Content-type: text/html; charset=UTF-8');
775
+
776
+ $this->setAction();
777
+
778
+ if (!$this->isInstalled()) {
779
+ if (!in_array($this->getAction(), array('index', 'connectInstallAll', 'empty', 'cleanCache'))) {
780
+ $this->setAction('index');
781
+ }
782
+ } else {
783
+ $this->session()->authenticate();
784
+ }
785
+
786
+ while (!$this->_isDispatched) {
787
+ $this->_isDispatched = true;
788
+
789
+ $method = $this->getActionMethod();
790
+ $this->$method();
791
+ }
792
+
793
+ $this->processRedirect();
794
+ }
795
+
796
+ /**
797
+ * Check root dir is writable
798
+ *
799
+ * @return bool
800
+ */
801
+ public function isWritable()
802
+ {
803
+ if (is_null($this->_writable)) {
804
+ $this->_writable = is_writable($this->getMageDir() . DIRECTORY_SEPARATOR)
805
+ && is_writable($this->filepath())
806
+ && (!file_exists($this->filepath('config.ini') || is_writable($this->filepath('config.ini'))));
807
+ }
808
+ return $this->_writable;
809
+ }
810
+
811
+ /**
812
+ * Check is Magento files downloaded
813
+ *
814
+ * @return bool
815
+ */
816
+ public function isDownloaded()
817
+ {
818
+ return file_exists($this->getMageFilename()) && file_exists($this->getVarFilename());
819
+ }
820
+
821
+ /**
822
+ * Check is Magento installed
823
+ *
824
+ * @return bool
825
+ */
826
+ public function isInstalled()
827
+ {
828
+ if (!$this->isDownloaded()) {
829
+ return false;
830
+ }
831
+ if (!class_exists('Mage', false)) {
832
+ if (!file_exists($this->getMageFilename())) {
833
+ return false;
834
+ }
835
+ include_once $this->getMageFilename();
836
+ Mage::setIsDownloader();
837
+ }
838
+ return Mage::isInstalled();
839
+ }
840
+
841
+ /**
842
+ * Retrieve Maintenance flag
843
+ *
844
+ * @return bool
845
+ */
846
+ protected function _getMaintenanceFlag()
847
+ {
848
+ if (is_null($this->_maintenance)) {
849
+ $this->_maintenance = !empty($_REQUEST['maintenance']) && $_REQUEST['maintenance'] == '1' ? true : false;
850
+ }
851
+ return $this->_maintenance;
852
+ }
853
+
854
+ /**
855
+ * Retrieve Maintenance Flag file path
856
+ *
857
+ * @return string
858
+ */
859
+ protected function _getMaintenanceFilePath()
860
+ {
861
+ if (is_null($this->_maintenanceFile)) {
862
+ $path = dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR;
863
+ $this->_maintenanceFile = $path . 'maintenance.flag';
864
+ }
865
+ return $this->_maintenanceFile;
866
+ }
867
+
868
+ /**
869
+ * Begin install package(s)
870
+ */
871
+ public function startInstall()
872
+ {
873
+ if ($this->_getMaintenanceFlag()) {
874
+ $maintenance_filename='maintenance.flag';
875
+ $config = $this->config();
876
+ if (!$this->isWritable() || strlen($config->__get('remote_config')) > 0) {
877
+ $ftpObj = new Mage_Connect_Ftp();
878
+ $ftpObj->connect($config->__get('remote_config'));
879
+ $tempFile = tempnam(sys_get_temp_dir(),'maintenance');
880
+ @file_put_contents($tempFile, 'maintenance');
881
+ $ftpObj->upload($maintenance_filename, $tempFile);
882
+ $ftpObj->close();
883
+ } else {
884
+ @file_put_contents($this->_getMaintenanceFilePath(), 'maintenance');
885
+ }
886
+ }
887
+ }
888
+
889
+ /**
890
+ * End install package(s)
891
+ */
892
+ public function endInstall()
893
+ {
894
+ //$connect
895
+ /** @var $connect Maged_Model_Connect */
896
+ $frontend = $this->model('connect', true)->connect()->getFrontend();
897
+ if (!($frontend instanceof Maged_Connect_Frontend)) {
898
+ $this->cleanCache();
899
+ }
900
+ }
901
+
902
+ protected function cleanCache()
903
+ {
904
+ $result = true;
905
+ $message = '';
906
+ try {
907
+ if ($this->isInstalled()) {
908
+ if (!empty($_REQUEST['clean_sessions'])) {
909
+ Mage::app()->cleanAllSessions();
910
+ $message .= 'Session cleaned successfully. ';
911
+ }
912
+ Mage::app()->cleanCache();
913
+
914
+ // reinit config and apply all updates
915
+ Mage::app()->getConfig()->reinit();
916
+ Mage_Core_Model_Resource_Setup::applyAllUpdates();
917
+ Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
918
+ $message .= 'Cache cleaned successfully';
919
+ } else {
920
+ $result = true;
921
+ }
922
+ } catch (Exception $e) {
923
+ $result = false;
924
+ $message = "Exception during cache and session cleaning: ".$e->getMessage();
925
+ $this->session()->addMessage('error', $message);
926
+ }
927
+
928
+ if ($result && $this->_getMaintenanceFlag()) {
929
+ $maintenance_filename='maintenance.flag';
930
+ $config = $this->config();
931
+ if (!$this->isWritable() && strlen($config->__get('remote_config')) > 0) {
932
+ $ftpObj = new Mage_Connect_Ftp();
933
+ $ftpObj->connect($config->__get('remote_config'));
934
+ $ftpObj->delete($maintenance_filename);
935
+ $ftpObj->close();
936
+ } else {
937
+ @unlink($this->_getMaintenanceFilePath());
938
+ }
939
+ }
940
+ return array('result' => $result, 'message' => $message);
941
+ }
942
+
943
+ /**
944
+ * Gets the current Magento Connect Manager (Downloader) version string
945
+ * @link http://www.magentocommerce.com/blog/new-community-edition-release-process/
946
+ *
947
+ * @return string
948
+ */
949
+ public static function getVersion()
950
+ {
951
+ $i = self::getVersionInfo();
952
+ return trim(
953
+ "{$i['major']}.{$i['minor']}.{$i['revision']}"
954
+ . ($i['patch'] != '' ? ".{$i['patch']}" : "")
955
+ . "-{$i['stability']}{$i['number']}",
956
+ '.-'
957
+ );
958
+ }
959
+
960
+ /**
961
+ * Gets the detailed Magento Connect Manager (Downloader) version information
962
+ * @link http://www.magentocommerce.com/blog/new-community-edition-release-process/
963
+ *
964
+ * @return array
965
+ */
966
+ public static function getVersionInfo()
967
+ {
968
+ return array(
969
+ 'major' => '1',
970
+ 'minor' => '5',
971
+ 'revision' => '0',
972
+ 'patch' => '0',
973
+ 'stability' => '',
974
+ 'number' => '',
975
+ );
976
+ }
977
+ }
downloader/Maged/Exception.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class Exception
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
33
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
+ */
35
+ class Maged_Exception extends Exception
36
+ {
37
+ }
downloader/Maged/Model.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class Model
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
33
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
+ */
35
+ class Maged_Model
36
+ {
37
+
38
+ /**
39
+ * Internal cache
40
+ *
41
+ * @var array
42
+ */
43
+ protected $_data;
44
+
45
+ /**
46
+ * Constructor
47
+ */
48
+ public function __construct()
49
+ {
50
+ $args = func_get_args();
51
+ if (empty($args[0])) {
52
+ $args[0] = array();
53
+ }
54
+ $this->_data = $args[0];
55
+
56
+ $this->_construct();
57
+ }
58
+
59
+ /**
60
+ * Constructor for covering
61
+ */
62
+ protected function _construct()
63
+ {
64
+
65
+ }
66
+
67
+ /**
68
+ * Retrieve controller
69
+ * @return Maged_Controller
70
+ */
71
+ public function controller()
72
+ {
73
+ return Maged_Controller::singleton();
74
+ }
75
+
76
+ /**
77
+ * Set value for key
78
+ *
79
+ * @param string $key
80
+ * @param mixed $value
81
+ * @return Maged_Model
82
+ */
83
+ public function set($key, $value)
84
+ {
85
+ $this->_data[$key] = $value;
86
+ return $this;
87
+ }
88
+
89
+ /**
90
+ * Get value by key
91
+ *
92
+ * @param string $key
93
+ * @return mixed
94
+ */
95
+ public function get($key)
96
+ {
97
+ return isset($this->_data[$key]) ? $this->_data[$key] : null;
98
+ }
99
+ }
downloader/Maged/Model/Config.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class config
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
33
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
+ */
35
+ class Maged_Model_Config extends Maged_Model_Config_Abstract
36
+ {
37
+ /**
38
+ * Get channel config class
39
+ * @return Maged_Model_Config_Interface
40
+ */
41
+ public function getChannelConfig()
42
+ {
43
+ $this->load();
44
+ $channel = trim($this->get('root_channel'));
45
+ if (!empty($channel)) {
46
+ try {
47
+ return $this->controller()->model('config_'.$channel, true);
48
+ } catch (Exception $e) {
49
+ throw new Exception('Not valid config.ini file.');
50
+ }
51
+ } else {
52
+ throw new Exception('Not valid config.ini file.');
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Save post data to config
58
+ *
59
+ * @param array $p
60
+ * @return Maged_Model_Config
61
+ */
62
+ public function saveConfigPost($p)
63
+ {
64
+ $configParams = array(
65
+ 'protocol',
66
+ 'preferred_state',
67
+ 'use_custom_permissions_mode',
68
+ 'mkdir_mode',
69
+ 'chmod_file_mode',
70
+ 'magento_root',
71
+ 'downloader_path',
72
+ 'root_channel_uri',
73
+ 'root_channel',
74
+ 'ftp',
75
+ );
76
+ foreach ($configParams as $paramName){
77
+ if (isset($p[$paramName])) {
78
+ $this->set($paramName, $p[$paramName]);
79
+ }
80
+ }
81
+ $this->save();
82
+ return $this;
83
+ }
84
+ }
downloader/Maged/Model/Config/Abstract.php ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class config
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
33
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
+ */
35
+ class Maged_Model_Config_Abstract extends Maged_Model
36
+ {
37
+ /**
38
+ * Retrive file name
39
+ *
40
+ * @return string
41
+ */
42
+ public function getFilename()
43
+ {
44
+ return $this->controller()->filepath('config.ini');
45
+ }
46
+
47
+ /**
48
+ * Load file
49
+ *
50
+ * @return Maged_Model_Config
51
+ */
52
+ public function load()
53
+ {
54
+ if (!file_exists($this->getFilename())) {
55
+ return $this;
56
+ }
57
+ $rows = file($this->getFilename());
58
+ if (!$rows) {
59
+ return $this;
60
+ }
61
+ foreach ($rows as $row) {
62
+ $arr = explode('=', $row, 2);
63
+ if (count($arr)!==2) {
64
+ continue;
65
+ }
66
+ $key = trim($arr[0]);
67
+ $value = trim($arr[1], " \t\"'\n\r");
68
+ if (!$key || $key[0]=='#' || $key[0]==';') {
69
+ continue;
70
+ }
71
+ $this->set($key, $value);
72
+ }
73
+ return $this;
74
+ }
75
+
76
+ /**
77
+ * Save file
78
+ *
79
+ * @return Maged_Model_Config
80
+ */
81
+ public function save()
82
+ {
83
+ if ((!is_writable($this->getFilename())&&is_file($this->getFilename()))||(dirname($this->getFilename())!=''&&!is_writable(dirname($this->getFilename())))) {
84
+ if(isset($this->_data['ftp'])&&!empty($this->_data['ftp'])&&strlen($this->get('downloader_path'))>0){
85
+ $confFile=$this->get('downloader_path').DIRECTORY_SEPARATOR.basename($this->getFilename());
86
+ $ftpObj = new Mage_Connect_Ftp();
87
+ $ftpObj->connect($this->_data['ftp']);
88
+ $tempFile = tempnam(sys_get_temp_dir(),'configini');
89
+ $fp = fopen($tempFile, 'w');
90
+ foreach ($this->_data as $k=>$v) {
91
+ fwrite($fp, $k.'='.$v."\n");
92
+ }
93
+ fclose($fp);
94
+ $ret=$ftpObj->upload($confFile, $tempFile);
95
+ $ftpObj->close();
96
+ }else{
97
+ /* @TODO: show Warning message*/
98
+ $this->controller()->session()
99
+ ->addMessage('warning', 'Invalid file permissions, could not save configuration.');
100
+ return $this;
101
+ }
102
+ /**/
103
+ }else{
104
+ $fp = fopen($this->getFilename(), 'w');
105
+ foreach ($this->_data as $k=>$v) {
106
+ fwrite($fp, $k.'='.$v."\n");
107
+ }
108
+ fclose($fp);
109
+ }
110
+ return $this;
111
+ }
112
+
113
+ /**
114
+ * Return channel label for channel name
115
+ *
116
+ * @param string $channel
117
+ * @return string
118
+ */
119
+ public function getChannelLabel($channel)
120
+ {
121
+ $channelLabel = '';
122
+ switch($channel)
123
+ {
124
+ case 'community':
125
+ $channelLabel = 'Magento Community Edition';
126
+ break;
127
+ default:
128
+ $channelLabel = $channel;
129
+ break;
130
+ }
131
+ return $channelLabel;
132
+ }
133
+ }
134
+ ?>
downloader/Maged/Model/Config/Community.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class config
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
33
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
+ */
35
+ class Maged_Model_Config_Community extends Maged_Model_Config_Abstract implements Maged_Model_Config_Interface
36
+ {
37
+
38
+ /**
39
+ * Initialization
40
+ */
41
+ protected function _construct()
42
+ {
43
+ $this->load();
44
+ }
45
+
46
+ /**
47
+ * Set data for Settings View
48
+ *
49
+ * @param Mage_Connect_Config $config
50
+ * @param Maged_View $view
51
+ * @return null
52
+ */
53
+ public function setInstallView($config, $view)
54
+ {
55
+ $view->set('channel_logo', 'logo');
56
+ }
57
+
58
+ /**
59
+ * Set data for Settings View
60
+ * @param Mage_Connect_Config $config
61
+ * @param Maged_View $view
62
+ * @return null
63
+ */
64
+ public function setSettingsView($config, $view)
65
+ {
66
+ }
67
+
68
+ /**
69
+ * Set session data for Settings
70
+ * @param array $post post data
71
+ * @param mixed $session Session object
72
+ * @return null
73
+ */
74
+ public function setSettingsSession($post, $session)
75
+ {
76
+ }
77
+
78
+ /**
79
+ * Get root channel URI
80
+ *
81
+ * @return string Root channel URI
82
+ */
83
+ public function getRootChannelUri(){
84
+ if (!$this->get('root_channel_uri')) {
85
+ $this->set('root_channel_uri', 'connect20.magentocommerce.com/community');
86
+ }
87
+ return $this->get('root_channel_uri');
88
+ }
89
+
90
+ /**
91
+ * Set config data from POST
92
+ *
93
+ * @param Mage_Connect_Config $config Config object
94
+ * @param array $post post data
95
+ * @return null
96
+ */
97
+ public function setPostData($config, &$post)
98
+ {
99
+ }
100
+
101
+ /**
102
+ * Set additional command options
103
+ *
104
+ * @param mixed $session Session object
105
+ * @param array $options
106
+ * @return null
107
+ */
108
+ public function setCommandOptions($session, &$options)
109
+ {
110
+ }
111
+ }
112
+ ?>
downloader/Maged/Model/Config/Interface.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class config
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
33
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
+ */
35
+ interface Maged_Model_Config_Interface
36
+ {
37
+
38
+ /**
39
+ * Set data for Settings View
40
+ *
41
+ * @param Mage_Connect_Config $config
42
+ * @param Maged_View $view
43
+ * @return null
44
+ */
45
+ public function setInstallView($config, $view);
46
+
47
+ /**
48
+ * Set data for Settings View
49
+ *
50
+ * @param mixed $session Session object
51
+ * @param Maged_View $view
52
+ * @return null
53
+ */
54
+ public function setSettingsView($session, $view);
55
+
56
+ /**
57
+ * Set session data for Settings
58
+ *
59
+ * @param array $post post data
60
+ * @param mixed $session Session object
61
+ * @return null
62
+ */
63
+ public function setSettingsSession($post, $session);
64
+
65
+ /**
66
+ * Set config data from POST
67
+ *
68
+ * @param Mage_Connect_Config $config Config object
69
+ * @param array $post post data
70
+ * @return boolean
71
+ */
72
+ public function setPostData($config, &$post);
73
+
74
+ /**
75
+ * Get root channel URI
76
+ *
77
+ * @return string Root channel URI
78
+ */
79
+ public function getRootChannelUri();
80
+
81
+ /**
82
+ * Set additional command options
83
+ *
84
+ * @param mixed $session Session object
85
+ * @param array $options
86
+ * @return null
87
+ */
88
+ public function setCommandOptions($session, &$options);
89
+ }
90
+ ?>
downloader/Maged/Model/Connect.php ADDED
@@ -0,0 +1,491 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ include_once "Maged/Connect.php";
28
+
29
+ /**
30
+ * Class for initialize Mage_Connect lib
31
+ *
32
+ * @category Mage
33
+ * @package Mage_Connect
34
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
35
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
36
+ */
37
+
38
+ class Maged_Model_Connect extends Maged_Model
39
+ {
40
+
41
+ /**
42
+ * Constructor
43
+ */
44
+ protected function _construct()
45
+ {
46
+ parent::_construct();
47
+ }
48
+
49
+ /**
50
+ * Retrive object of Maged_Connect
51
+ *
52
+ * @return Maged_Connect
53
+ */
54
+ public function connect()
55
+ {
56
+ return Maged_Connect::getInstance();
57
+ }
58
+
59
+ /**
60
+ * Install All Magento
61
+ *
62
+ * @param boolean $force
63
+ */
64
+ public function installAll($force=false, $chanName='')
65
+ {
66
+ $options = array('install_all'=>true);
67
+ if ($force) {
68
+ $this->connect()->cleanSconfig();
69
+ $options['force'] = 1;
70
+ }
71
+ $packages = array(
72
+ 'Mage_All_Latest',
73
+ );
74
+ $connectConfig = $this->connect()->getConfig();
75
+ $ftp = $connectConfig->remote_config;
76
+ if (!empty($ftp)) {
77
+ $options['ftp'] = $ftp;
78
+ }
79
+ $params = array();
80
+
81
+ $uri = $this->controller()->channelConfig()->getRootChannelUri();
82
+
83
+ $this->controller()->channelConfig()->setCommandOptions($this->controller()->session(), $options);
84
+
85
+ $connectConfig->root_channel = $chanName;
86
+ foreach ($packages as $package) {
87
+ $params[] = $uri;
88
+ $params[] = $package;
89
+ }
90
+ $this->connect()->runHtmlConsole(array('command'=>'install', 'options'=>$options, 'params'=>$params));
91
+ }
92
+
93
+ /**
94
+ * Prepare to install package
95
+ *
96
+ * @param string $id
97
+ * @return array
98
+ */
99
+ public function prepareToInstall($id)
100
+ {
101
+ $match = array();
102
+ if (!$this->checkExtensionKey($id, $match)) {
103
+ echo('Invalid package identifier provided: '.$id);
104
+ exit;
105
+ }
106
+
107
+ $channel = $match[1];
108
+ $package = $match[2];
109
+ $version = (!empty($match[3]) ? trim($match[3],'/\-') : '');
110
+
111
+ $connect = $this->connect();
112
+ $sconfig = $connect->getSingleConfig();
113
+
114
+ $options = array();
115
+ $params = array($channel, $package, $version, $version);
116
+ $this->controller()->channelConfig()->setCommandOptions($this->controller()->session(), $options);
117
+
118
+ $connect->run('package-prepare', $options, $params);
119
+ $output = $connect->getOutput();
120
+ $errors = $connect->getFrontend()->getErrors();
121
+ $package_error = array();
122
+ foreach ($errors as $error){
123
+ if (isset($error[1])){
124
+ $package_error[] = $error[1];
125
+ }
126
+ }
127
+
128
+ $packages = array();
129
+ if (is_array($output) && isset($output['package-prepare'])){
130
+ $packages = array_merge($output['package-prepare'], array('errors'=>array('error'=>$package_error)));
131
+ } elseif (is_array($output) && !empty($package_error)) {
132
+ $packages = array('errors'=>array('error'=>$package_error));
133
+ }
134
+ return $packages;
135
+ }
136
+
137
+
138
+ /**
139
+ * Retrieve all installed packages
140
+ *
141
+ * @return array
142
+ */
143
+ public function getAllInstalledPackages()
144
+ {
145
+ $connect = $this->connect();
146
+ $sconfig = $connect->getSingleConfig(true);
147
+ $connect->run('list-installed');
148
+ $output = $connect->getOutput();
149
+ $packages = array();
150
+ if (is_array($output) && isset($output['list-installed']['data'])){
151
+ $packages = $output['list-installed']['data'];
152
+ } else {
153
+
154
+ }
155
+ foreach ($packages as $channel=>$package) {
156
+ foreach ($package as $name=>$data) {
157
+ $summary = $sconfig->getPackageObject($channel, $name)->getSummary();
158
+ $addition = array('summary'=>$summary, 'upgrade_versions'=>array(), 'upgrade_latest'=>'');
159
+ $packages[$channel][$name] = array_merge($data, $addition);
160
+ }
161
+ }
162
+
163
+ if (!empty($_GET['updates'])) {
164
+ $options = array();
165
+ $this->controller()->channelConfig()->setCommandOptions($this->controller()->session(), $options);
166
+ $result = $connect->run('list-upgrades', $options);
167
+ $output = $connect->getOutput();
168
+ if (is_array($output)) {
169
+ $channelData = $output;
170
+ if (!empty($channelData['list-upgrades']['data']) && is_array($channelData['list-upgrades']['data'])) {
171
+ foreach ($channelData['list-upgrades']['data'] as $channel=>$package) {
172
+ foreach ($package as $name=>$data) {
173
+ if (!isset($packages[$channel][$name])) {
174
+ continue;
175
+ }
176
+ $packages[$channel][$name]['upgrade_latest'] = $data['to'].' ('.$data['from'].')';
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ $states = array('snapshot'=>0, 'devel'=>1, 'alpha'=>2, 'beta'=>3, 'stable'=>4);
184
+ $preferredState = $states[$this->getPreferredState()];
185
+
186
+ foreach ($packages as $channel=>&$package) {
187
+ foreach ($package as $name=>&$data) {
188
+ $actions = array();
189
+ $systemPkg = $name==='Mage_Downloader';
190
+ if (!empty($data['upgrade_latest'])) {
191
+ $status = 'upgrade-available';
192
+ $releases = array();
193
+ $connect->run('info', array(), array($channel, $name));
194
+ $output = $connect->getOutput();
195
+ if (!empty($output['info']['releases'])) {
196
+ foreach ($output['info']['releases'] as $release) {
197
+ $stability = $packages[$channel][$name]['stability'];
198
+ if ($states[$release['s']] < min($preferredState, $states[$stability])) {
199
+ continue;
200
+ }
201
+ if (version_compare($release['v'], $packages[$channel][$name]['version']) < 1) {
202
+ continue;
203
+ }
204
+ $releases[$release['v']] = $release['v'].' ('.$release['s'].')';
205
+ }
206
+ }
207
+
208
+ if ($releases) {
209
+ uksort($releases, 'version_compare');
210
+ foreach ($releases as $version => $release) {
211
+ $actions['upgrade|'.$version] = 'Upgrade to '.$release;
212
+ }
213
+ } else {
214
+ $a = explode(' ', $data['upgrade_latest'], 2);
215
+ $actions['upgrade|'.$a[0]] = 'Upgrade';
216
+ }
217
+ if (!$systemPkg) {
218
+ $actions['uninstall'] = 'Uninstall';
219
+ }
220
+ } else {
221
+ $status = 'installed';
222
+ $actions['reinstall'] = 'Reinstall';
223
+ if (!$systemPkg) {
224
+ $actions['uninstall'] = 'Uninstall';
225
+ }
226
+ }
227
+ $packages[$channel][$name]['actions'] = $actions;
228
+ $packages[$channel][$name]['status'] = $status;
229
+ }
230
+ }
231
+ return $packages;
232
+ }
233
+
234
+ /**
235
+ * Run packages action
236
+ *
237
+ * @param mixed $packages
238
+ */
239
+ public function applyPackagesActions($packages, $ignoreLocalModification='')
240
+ {
241
+ $actions = array();
242
+ foreach ($packages as $package=>$action) {
243
+ if ($action) {
244
+ $a = explode('|', $package);
245
+ $b = explode('|', $action);
246
+ $package = $a[1];
247
+ $channel = $a[0];
248
+ $version = '';
249
+ if ($b[0]=='upgrade') {
250
+ $version = $b[1];
251
+ }
252
+ $actions[$b[0]][] = array($channel, $package, $version, $version);
253
+ }
254
+ }
255
+ if (empty($actions)) {
256
+ $this->connect()->runHtmlConsole('No actions selected');
257
+ exit;
258
+ }
259
+
260
+ $this->controller()->startInstall();
261
+
262
+ $options = array();
263
+ if (!empty($ignoreLocalModification)) {
264
+ $options = array('ignorelocalmodification'=>1);
265
+ }
266
+ if(!$this->controller()->isWritable()||strlen($this->connect()->getConfig()->__get('remote_config'))>0){
267
+ $options['ftp'] = $this->connect()->getConfig()->__get('remote_config');
268
+ }
269
+
270
+ $this->controller()->channelConfig()->setCommandOptions($this->controller()->session(), $options);
271
+
272
+ foreach ($actions as $action=>$packages) {
273
+ foreach ($packages as $package) {
274
+ switch ($action) {
275
+ case 'install': case 'uninstall': case 'upgrade':
276
+ $this->connect()->runHtmlConsole(array(
277
+ 'command'=>$action,
278
+ 'options'=>$options,
279
+ 'params'=>$package
280
+ ));
281
+ break;
282
+
283
+ case 'reinstall':
284
+ $package_info = $this->connect()->getSingleConfig()->getPackage($package[0], $package[1]);
285
+ if (isset($package_info['version'])) {
286
+ $package[2] = $package_info['version'];
287
+ $package[3] = $package_info['version'];
288
+ }
289
+ $this->connect()->runHtmlConsole(array(
290
+ 'command'=>'install',
291
+ 'options'=>array_merge($options, array('force'=>1, 'nodeps'=>1)),
292
+ 'params'=>$package
293
+ ));
294
+ break;
295
+ }
296
+ }
297
+ }
298
+
299
+ $this->controller()->endInstall();
300
+ }
301
+
302
+
303
+ public function installUploadedPackage($file)
304
+ {
305
+ $this->controller()->startInstall();
306
+
307
+ $options = array();
308
+ if(!$this->controller()->isWritable()||strlen($this->connect()->getConfig()->__get('remote_config'))>0){
309
+ $options['ftp'] = $this->connect()->getConfig()->__get('remote_config');
310
+ }
311
+ $this->connect()->runHtmlConsole(array(
312
+ 'command'=>'install-file',
313
+ 'options'=>$options,
314
+ 'params'=>array($file),
315
+ ));
316
+ $this->controller()->endInstall();
317
+ }
318
+
319
+ /**
320
+ * Install package by id
321
+ *
322
+ * @param string $id
323
+ * @param boolean $force
324
+ */
325
+ public function installPackage($id, $force=false)
326
+ {
327
+ $match = array();
328
+ if (!$this->checkExtensionKey($id, $match)) {
329
+ $this->connect()->runHtmlConsole('Invalid package identifier provided: '.$id);
330
+ exit;
331
+ }
332
+
333
+ $channel = $match[1];
334
+ $package = $match[2];//.(!empty($match[3]) ? $match[3] : '');
335
+ $version = (!empty($match[3]) ? trim($match[3],'/\-') : '');
336
+
337
+ $this->controller()->startInstall();
338
+
339
+ $options = array();
340
+ if ($force) {
341
+ $options['force'] = 1;
342
+ }
343
+ if(!$this->controller()->isWritable()||strlen($this->connect()->getConfig()->__get('remote_config'))>0){
344
+ $options['ftp'] = $this->connect()->getConfig()->__get('remote_config');
345
+ }
346
+
347
+ $this->controller()->channelConfig()->setCommandOptions($this->controller()->session(), $options);
348
+
349
+ $this->connect()->runHtmlConsole(array(
350
+ 'command'=>'install',
351
+ 'options'=>$options,
352
+ 'params'=>array(0=>$channel, 1=>$package, 2=>$version),
353
+ ));
354
+
355
+ $this->controller()->endInstall();
356
+ }
357
+
358
+ /**
359
+ * Retrieve stability choosen client
360
+ *
361
+ * @return string alpha, beta, ...
362
+ */
363
+ public function getPreferredState()
364
+ {
365
+ if (is_null($this->get('preferred_state'))) {
366
+ $connectConfig = $this->connect()->getConfig();
367
+ $this->set('preferred_state', $connectConfig->__get('preferred_state'));
368
+ }
369
+ return $this->get('preferred_state');
370
+ }
371
+
372
+ /**
373
+ * Retrieve protocol choosen client
374
+ *
375
+ * @return string http, ftp
376
+ */
377
+ public function getProtocol()
378
+ {
379
+ if (is_null($this->get('protocol'))) {
380
+ $connectConfig = $this->connect()->getConfig();
381
+ $this->set('protocol', $connectConfig->__get('protocol'));
382
+ }
383
+ return $this->get('protocol');
384
+ }
385
+
386
+ /**
387
+ * Validate settings post data.
388
+ *
389
+ * @param array $p
390
+ */
391
+ public function validateConfigPost($p)
392
+ {
393
+ $errors = array();
394
+ $configTestFile = 'connect.cfgt';
395
+ $configObj = $this->connect()->getConfig();
396
+ if ('ftp' == $p['deployment_type'] || '1' == $p['inst_protocol']) {
397
+ /*check ftp*/
398
+
399
+ $confFile = $configObj->downloader_path.DIRECTORY_SEPARATOR.$configTestFile;
400
+ try {
401
+ $ftpObj = new Mage_Connect_Ftp();
402
+ $ftpObj->connect($p['ftp']);
403
+ $tempFile = tempnam(sys_get_temp_dir(),'config');
404
+ $serial = md5('config test file');
405
+ $f = @fopen($tempFile, "w+");
406
+ @fwrite($f, $serial);
407
+ @fclose($f);
408
+ $ret=$ftpObj->upload($confFile, $tempFile);
409
+
410
+ //read file
411
+ if (!$errors && is_file($configTestFile)) {
412
+ $size = filesize($configTestFile);
413
+ if(!$size) {
414
+ $errors[]='Unable to read saved settings. Please check Installation Path of FTP Connection.';
415
+ }
416
+
417
+ if (!$errors) {
418
+ $f = @fopen($configTestFile, "r");
419
+ @fseek($f, 0, SEEK_SET);
420
+
421
+ $contents = @fread($f, strlen($serial));
422
+ if ($serial != $contents) {
423
+ $errors[]='Wrong Installation Path of FTP Connection.';
424
+ }
425
+ fclose($f);
426
+ }
427
+ } else {
428
+ $errors[] = 'Unable to read saved settings. Please check Installation Path of FTP Connection.';
429
+ }
430
+ $ftpObj->delete($confFile);
431
+ $ftpObj->close();
432
+ } catch (Exception $e) {
433
+ $errors[] = 'Deployment FTP Error. ' . $e->getMessage();
434
+ }
435
+ } else {
436
+ $p['ftp'] = '';
437
+ }
438
+
439
+ if ('1' == $p['use_custom_permissions_mode']) {
440
+ /*check permissions*/
441
+ if (octdec(intval($p['mkdir_mode'])) < 73 || octdec(intval($p['mkdir_mode'])) > 511) {
442
+ $errors[]='Folders permissions not valid. ';
443
+ }
444
+ if (octdec(intval($p['chmod_file_mode'])) < 73 || octdec(intval($p['chmod_file_mode'])) > 511) {
445
+ $errors[]='Files permissions not valid. ';
446
+ }
447
+ }
448
+ //$this->controller()->session()->addMessage('success', 'Settings has been successfully saved');
449
+ return $errors;
450
+ }
451
+ /**
452
+ * Save settings.
453
+ *
454
+ * @param array $p
455
+ */
456
+ public function saveConfigPost($p)
457
+ {
458
+ $configObj = $this->connect()->getConfig();
459
+ if ('ftp' == $p['deployment_type'] || '1' == $p['inst_protocol']){
460
+ $this->set('ftp',$p['ftp']);
461
+ } else {
462
+ $p['ftp'] = '';
463
+ }
464
+ $configObj->remote_config = $p['ftp'];
465
+ $configObj->preferred_state = $p['preferred_state'];
466
+ $configObj->protocol = $p['protocol'];
467
+ $configObj->use_custom_permissions_mode = $p['use_custom_permissions_mode'];
468
+ if ('1' == $p['use_custom_permissions_mode']) {
469
+ $configObj->global_dir_mode = octdec(intval($p['mkdir_mode']));
470
+ $configObj->global_file_mode = octdec(intval($p['chmod_file_mode']));
471
+ }
472
+ if ($configObj->save()) {
473
+ $this->controller()->session()->addMessage('success', 'Settings has been successfully saved');
474
+ } else {
475
+ $this->controller()->session()->addMessage('error', 'Settings cannot be saved');
476
+ }
477
+ return $this;
478
+ }
479
+
480
+ /**
481
+ * Check Extension Key
482
+ *
483
+ * @param string $id
484
+ * @param array $match
485
+ * @return int
486
+ */
487
+ public function checkExtensionKey($id, &$match)
488
+ {
489
+ return preg_match('#^([^ ]+)\/([^-]+)(-.+)?$#', $id, $match);
490
+ }
491
+ }
downloader/Maged/Model/Connect/Request.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class request
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
33
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
+ */
35
+ class Maged_Model_Connect_Request extends Maged_Model
36
+ {
37
+ protected function _construct()
38
+ {
39
+ parent::_construct();
40
+ $this->set('success_callback', 'clear_cache({success:parent.onSuccess, fail:parent.onFailure})');
41
+ $this->set('failure_callback', 'parent.onFailure()');
42
+ }
43
+ }
downloader/Maged/Model/Dowloader.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ class Maged_Model_Downloader extends Maged_Model
28
+ {
29
+
30
+ }
downloader/Maged/Model/Session.php ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class session
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
33
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
+ */
35
+ class Maged_Model_Session extends Maged_Model
36
+ {
37
+ /**
38
+ * Session
39
+ *
40
+ * @var Mage_Admin_Model_Session
41
+ */
42
+ protected $_session;
43
+
44
+ /**
45
+ * Init session
46
+ *
47
+ * @return Maged_Model_Session
48
+ */
49
+ public function start()
50
+ {
51
+ if (class_exists('Mage') && Mage::isInstalled()) {
52
+ // initialize Magento Config
53
+ Mage::app();
54
+ $this->_session = Mage::getSingleton('admin/session');
55
+ } else {
56
+ session_start();
57
+ }
58
+ return $this;
59
+ }
60
+
61
+ /**
62
+ * Get value by key
63
+ *
64
+ * @param string $key
65
+ * @return mixed
66
+ */
67
+ public function get($key)
68
+ {
69
+ return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
70
+ }
71
+
72
+ /**
73
+ * Set value for key
74
+ *
75
+ * @param string $key
76
+ * @param mixed $value
77
+ */
78
+ public function set($key, $value)
79
+ {
80
+ $_SESSION[$key] = $value;
81
+ return $this;
82
+ }
83
+
84
+ /**
85
+ * Authentication to downloader
86
+ */
87
+ public function authenticate()
88
+ {
89
+ if (!$this->_session) {
90
+ return $this;
91
+ }
92
+
93
+ if (!empty($_GET['return'])) {
94
+ $this->set('return_url', $_GET['return']);
95
+ }
96
+
97
+ if ($this->_checkUserAccess()) {
98
+ return $this;
99
+ }
100
+
101
+ if (!$this->controller()->isInstalled()) {
102
+ return $this;
103
+ }
104
+
105
+ try {
106
+ if ( (isset($_POST['username']) && empty($_POST['username']))
107
+ || (isset($_POST['password']) && empty($_POST['password']))) {
108
+ $this->addMessage('error', 'Invalid user name or password');
109
+ }
110
+ if (empty($_POST['username']) || empty($_POST['password'])) {
111
+ $this->controller()->setAction('login');
112
+ return $this;
113
+ }
114
+ $user = $this->_session->login($_POST['username'], $_POST['password']);
115
+ $this->_session->refreshAcl();
116
+ if ($this->_checkUserAccess($user)) {
117
+ return $this;
118
+ }
119
+ } catch (Exception $e) {
120
+ $this->addMessage('error', $e->getMessage());
121
+ }
122
+
123
+ $this->controller()
124
+ ->redirect(
125
+ $this->controller()->url('loggedin'),
126
+ true
127
+ );
128
+ }
129
+
130
+ /**
131
+ * Check is user logged in and permissions
132
+ *
133
+ * @param Mage_Admin_Model_User|null $user
134
+ * @return bool
135
+ */
136
+ protected function _checkUserAccess($user = null)
137
+ {
138
+ if ($user && !$user->getId()) {
139
+ $this->addMessage('error', 'Invalid user name or password');
140
+ $this->controller()->setAction('login');
141
+ } elseif ($this->getUserId() || ($user && $user->getId())) {
142
+ if ($this->_session->isAllowed('all')) {
143
+ return true;
144
+ } else {
145
+ $this->logout();
146
+ $this->addMessage('error', 'Access Denied', true);
147
+ $this->controller()->setAction('login');
148
+ }
149
+ }
150
+ return false;
151
+ }
152
+
153
+ /**
154
+ * Log Out
155
+ *
156
+ * @return Maged_Model_Session
157
+ */
158
+ public function logout()
159
+ {
160
+ if (!$this->_session) {
161
+ return $this;
162
+ }
163
+ $this->_session->unsUser();
164
+ return $this;
165
+ }
166
+
167
+ /**
168
+ * Retrieve user
169
+ *
170
+ * @return mixed
171
+ */
172
+ public function getUserId()
173
+ {
174
+ if (($session = $this->_session) && ($user = $session->getUser())) {
175
+ return $user->getId();
176
+ }
177
+ return false;
178
+ }
179
+
180
+ /**
181
+ * Add Message
182
+ *
183
+ * @param string $type
184
+ * @param string $msg
185
+ * @param string $clear
186
+ * @return Maged_Model_Session
187
+ */
188
+ public function addMessage($type, $msg, $clear = false)
189
+ {
190
+ $msgs = $this->getMessages($clear);
191
+ $msgs[$type][] = $msg;
192
+ $this->set('messages', $msgs);
193
+ return $this;
194
+ }
195
+
196
+ /**
197
+ * Retrieve messages from cache
198
+ *
199
+ * @param boolean $clear
200
+ * @return mixed
201
+ */
202
+ public function getMessages($clear = true)
203
+ {
204
+ $msgs = $this->get('messages');
205
+ $msgs = $msgs ? $msgs : array();
206
+ if ($clear) {
207
+ unset($_SESSION['messages']);
208
+ }
209
+ return $msgs;
210
+ }
211
+
212
+ /**
213
+ * Retrieve url to adminhtml
214
+ *
215
+ * @return string
216
+ */
217
+ public function getReturnUrl()
218
+ {
219
+ if (!$this->_session || !$this->_session->isLoggedIn()) {
220
+ return '';
221
+ }
222
+ return Mage::getSingleton('adminhtml/url')->getUrl('adminhtml');
223
+ }
224
+ }
downloader/Maged/View.php ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class for viewer
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @copyright Copyright (c) 2009 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
33
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
+ */
35
+ class Maged_View
36
+ {
37
+ /**
38
+ * Internal cache
39
+ *
40
+ * @var array
41
+ */
42
+ protected $_data = array();
43
+
44
+ /**
45
+ * Constructor
46
+ */
47
+ public function __construct()
48
+ {
49
+
50
+ }
51
+
52
+ /**
53
+ * Retrieve Controller as singleton
54
+ *
55
+ * @return Maged_Controller
56
+ */
57
+ public function controller()
58
+ {
59
+ return Maged_Controller::singleton();
60
+ }
61
+
62
+ /**
63
+ * Create url by action and params
64
+ *
65
+ * @param mixed $action
66
+ * @param mixed $params
67
+ * @return string
68
+ */
69
+ public function url($action='', $params=array())
70
+ {
71
+ return $this->controller()->url($action, $params);
72
+ }
73
+
74
+ /**
75
+ * Retrieve base url
76
+ *
77
+ * @return string
78
+ */
79
+ public function baseUrl()
80
+ {
81
+ return str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']));
82
+ }
83
+
84
+ /**
85
+ * Retrieve url of magento
86
+ *
87
+ * @return string
88
+ */
89
+ public function mageUrl()
90
+ {
91
+ return str_replace('\\', '/', dirname($this->baseUrl()));
92
+ }
93
+
94
+ /**
95
+ * Include template
96
+ *
97
+ * @param string $name
98
+ * @return string
99
+ */
100
+ public function template($name)
101
+ {
102
+ ob_start();
103
+ include $this->controller()->filepath('template/'.$name);
104
+ return ob_get_clean();
105
+ }
106
+
107
+ /**
108
+ * Set value for key
109
+ *
110
+ * @param string $key
111
+ * @param mixed $value
112
+ * @return Maged_Controller
113
+ */
114
+ public function set($key, $value)
115
+ {
116
+ $this->_data[$key] = $value;
117
+ return $this;
118
+ }
119
+
120
+ /**
121
+ * Get value by key
122
+ *
123
+ * @param string $key
124
+ * @return mixed
125
+ */
126
+ public function get($key)
127
+ {
128
+ return isset($this->_data[$key]) ? $this->_data[$key] : null;
129
+ }
130
+
131
+ /**
132
+ * Translator
133
+ *
134
+ * @param string $string
135
+ * @return string
136
+ */
137
+ public function __($string)
138
+ {
139
+ return $string;
140
+ }
141
+
142
+ /**
143
+ * Retrieve link for header menu
144
+ *
145
+ * @param mixed $action
146
+ */
147
+ public function getNavLinkParams($action)
148
+ {
149
+ $params = 'href="'.$this->url($action).'"';
150
+ if ($this->controller()->getAction()==$action) {
151
+ $params .= ' class="active"';
152
+ }
153
+ return $params;
154
+ }
155
+ }
downloader/config.ini ADDED
@@ -0,0 +1 @@
 
1
+ root_channel=community
downloader/index.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ if (version_compare(phpversion(), '5.2.0', '<')===true) {
28
+ echo '<div style="font:12px/1.35em arial, helvetica, sans-serif;"><div style="margin:0 0 25px 0; border-bottom:1px solid #ccc;"><h3 style="margin:0; font-size:1.7em; font-weight:normal; text-transform:none; text-align:left; color:#2f2f2f;">Whoops, it looks like you have an invalid PHP version.</h3></div><p>Magento supports PHP 5.2.0 or newer. <a href="http://www.magentocommerce.com/install" target="">Find out</a> how to install</a> Magento using PHP-CGI as a work-around.</p></div>';
29
+ exit;
30
+ }
31
+
32
+ require_once("lib/Mage/Autoload/Simple.php");
33
+ Mage_Autoload_Simple::register();
34
+
35
+ umask(0);
36
+ Maged_Controller::run();
downloader/js/prototype.js ADDED
@@ -0,0 +1,3277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Prototype JavaScript framework, version 1.5.1.1
2
+ * (c) 2005-2007 Sam Stephenson
3
+ *
4
+ * Prototype is freely distributable under the terms of an MIT-style license.
5
+ * For details, see the Prototype web site: http://www.prototypejs.org/
6
+ *
7
+ /*--------------------------------------------------------------------------*/
8
+
9
+ var Prototype = {
10
+ Version: '1.5.1.1',
11
+
12
+ Browser: {
13
+ IE: !!(window.attachEvent && !window.opera),
14
+ Opera: !!window.opera,
15
+ WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
16
+ Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
17
+ },
18
+
19
+ BrowserFeatures: {
20
+ XPath: !!document.evaluate,
21
+ ElementExtensions: !!window.HTMLElement,
22
+ SpecificElementExtensions:
23
+ (document.createElement('div').__proto__ !==
24
+ document.createElement('form').__proto__)
25
+ },
26
+
27
+ ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
28
+ JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
29
+
30
+ emptyFunction: function() { },
31
+ K: function(x) { return x }
32
+ }
33
+
34
+ var Class = {
35
+ create: function() {
36
+ return function() {
37
+ this.initialize.apply(this, arguments);
38
+ }
39
+ }
40
+ }
41
+
42
+ var Abstract = new Object();
43
+
44
+ Object.extend = function(destination, source) {
45
+ for (var property in source) {
46
+ destination[property] = source[property];
47
+ }
48
+ return destination;
49
+ }
50
+
51
+ Object.extend(Object, {
52
+ inspect: function(object) {
53
+ try {
54
+ if (object === undefined) return 'undefined';
55
+ if (object === null) return 'null';
56
+ return object.inspect ? object.inspect() : object.toString();
57
+ } catch (e) {
58
+ if (e instanceof RangeError) return '...';
59
+ throw e;
60
+ }
61
+ },
62
+
63
+ toJSON: function(object) {
64
+ var type = typeof object;
65
+ switch(type) {
66
+ case 'undefined':
67
+ case 'function':
68
+ case 'unknown': return;
69
+ case 'boolean': return object.toString();
70
+ }
71
+ if (object === null) return 'null';
72
+ if (object.toJSON) return object.toJSON();
73
+ if (object.ownerDocument === document) return;
74
+ var results = [];
75
+ for (var property in object) {
76
+ var value = Object.toJSON(object[property]);
77
+ if (value !== undefined)
78
+ results.push(property.toJSON() + ': ' + value);
79
+ }
80
+ return '{' + results.join(', ') + '}';
81
+ },
82
+
83
+ keys: function(object) {
84
+ var keys = [];
85
+ for (var property in object)
86
+ keys.push(property);
87
+ return keys;
88
+ },
89
+
90
+ values: function(object) {
91
+ var values = [];
92
+ for (var property in object)
93
+ values.push(object[property]);
94
+ return values;
95
+ },
96
+
97
+ clone: function(object) {
98
+ return Object.extend({}, object);
99
+ }
100
+ });
101
+
102
+ Function.prototype.bind = function() {
103
+ var __method = this, args = $A(arguments), object = args.shift();
104
+ return function() {
105
+ return __method.apply(object, args.concat($A(arguments)));
106
+ }
107
+ }
108
+
109
+ Function.prototype.bindAsEventListener = function(object) {
110
+ var __method = this, args = $A(arguments), object = args.shift();
111
+ return function(event) {
112
+ return __method.apply(object, [event || window.event].concat(args));
113
+ }
114
+ }
115
+
116
+ Object.extend(Number.prototype, {
117
+ toColorPart: function() {
118
+ return this.toPaddedString(2, 16);
119
+ },
120
+
121
+ succ: function() {
122
+ return this + 1;
123
+ },
124
+
125
+ times: function(iterator) {
126
+ $R(0, this, true).each(iterator);
127
+ return this;
128
+ },
129
+
130
+ toPaddedString: function(length, radix) {
131
+ var string = this.toString(radix || 10);
132
+ return '0'.times(length - string.length) + string;
133
+ },
134
+
135
+ toJSON: function() {
136
+ return isFinite(this) ? this.toString() : 'null';
137
+ }
138
+ });
139
+
140
+ Date.prototype.toJSON = function() {
141
+ return '"' + this.getFullYear() + '-' +
142
+ (this.getMonth() + 1).toPaddedString(2) + '-' +
143
+ this.getDate().toPaddedString(2) + 'T' +
144
+ this.getHours().toPaddedString(2) + ':' +
145
+ this.getMinutes().toPaddedString(2) + ':' +
146
+ this.getSeconds().toPaddedString(2) + '"';
147
+ };
148
+
149
+ var Try = {
150
+ these: function() {
151
+ var returnValue;
152
+
153
+ for (var i = 0, length = arguments.length; i < length; i++) {
154
+ var lambda = arguments[i];
155
+ try {
156
+ returnValue = lambda();
157
+ break;
158
+ } catch (e) {}
159
+ }
160
+
161
+ return returnValue;
162
+ }
163
+ }
164
+
165
+ /*--------------------------------------------------------------------------*/
166
+
167
+ var PeriodicalExecuter = Class.create();
168
+ PeriodicalExecuter.prototype = {
169
+ initialize: function(callback, frequency) {
170
+ this.callback = callback;
171
+ this.frequency = frequency;
172
+ this.currentlyExecuting = false;
173
+
174
+ this.registerCallback();
175
+ },
176
+
177
+ registerCallback: function() {
178
+ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
179
+ },
180
+
181
+ stop: function() {
182
+ if (!this.timer) return;
183
+ clearInterval(this.timer);
184
+ this.timer = null;
185
+ },
186
+
187
+ onTimerEvent: function() {
188
+ if (!this.currentlyExecuting) {
189
+ try {
190
+ this.currentlyExecuting = true;
191
+ this.callback(this);
192
+ } finally {
193
+ this.currentlyExecuting = false;
194
+ }
195
+ }
196
+ }
197
+ }
198
+ Object.extend(String, {
199
+ interpret: function(value) {
200
+ return value == null ? '' : String(value);
201
+ },
202
+ specialChar: {
203
+ '\b': '\\b',
204
+ '\t': '\\t',
205
+ '\n': '\\n',
206
+ '\f': '\\f',
207
+ '\r': '\\r',
208
+ '\\': '\\\\'
209
+ }
210
+ });
211
+
212
+ Object.extend(String.prototype, {
213
+ gsub: function(pattern, replacement) {
214
+ var result = '', source = this, match;
215
+ replacement = arguments.callee.prepareReplacement(replacement);
216
+
217
+ while (source.length > 0) {
218
+ if (match = source.match(pattern)) {
219
+ result += source.slice(0, match.index);
220
+ result += String.interpret(replacement(match));
221
+ source = source.slice(match.index + match[0].length);
222
+ } else {
223
+ result += source, source = '';
224
+ }
225
+ }
226
+ return result;
227
+ },
228
+
229
+ sub: function(pattern, replacement, count) {
230
+ replacement = this.gsub.prepareReplacement(replacement);
231
+ count = count === undefined ? 1 : count;
232
+
233
+ return this.gsub(pattern, function(match) {
234
+ if (--count < 0) return match[0];
235
+ return replacement(match);
236
+ });
237
+ },
238
+
239
+ scan: function(pattern, iterator) {
240
+ this.gsub(pattern, iterator);
241
+ return this;
242
+ },
243
+
244
+ truncate: function(length, truncation) {
245
+ length = length || 30;
246
+ truncation = truncation === undefined ? '...' : truncation;
247
+ return this.length > length ?
248
+ this.slice(0, length - truncation.length) + truncation : this;
249
+ },
250
+
251
+ strip: function() {
252
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
253
+ },
254
+
255
+ stripTags: function() {
256
+ return this.replace(/<\/?[^>]+>/gi, '');
257
+ },
258
+
259
+ stripScripts: function() {
260
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
261
+ },
262
+
263
+ extractScripts: function() {
264
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
265
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
266
+ return (this.match(matchAll) || []).map(function(scriptTag) {
267
+ return (scriptTag.match(matchOne) || ['', ''])[1];
268
+ });
269
+ },
270
+
271
+ evalScripts: function() {
272
+ return this.extractScripts().map(function(script) { return eval(script) });
273
+ },
274
+
275
+ escapeHTML: function() {
276
+ var self = arguments.callee;
277
+ self.text.data = this;
278
+ return self.div.innerHTML;
279
+ },
280
+
281
+ unescapeHTML: function() {
282
+ var div = document.createElement('div');
283
+ div.innerHTML = this.stripTags();
284
+ return div.childNodes[0] ? (div.childNodes.length > 1 ?
285
+ $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
286
+ div.childNodes[0].nodeValue) : '';
287
+ },
288
+
289
+ toQueryParams: function(separator) {
290
+ var match = this.strip().match(/([^?#]*)(#.*)?$/);
291
+ if (!match) return {};
292
+
293
+ return match[1].split(separator || '&').inject({}, function(hash, pair) {
294
+ if ((pair = pair.split('='))[0]) {
295
+ var key = decodeURIComponent(pair.shift());
296
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
297
+ if (value != undefined) value = decodeURIComponent(value);
298
+
299
+ if (key in hash) {
300
+ if (hash[key].constructor != Array) hash[key] = [hash[key]];
301
+ hash[key].push(value);
302
+ }
303
+ else hash[key] = value;
304
+ }
305
+ return hash;
306
+ });
307
+ },
308
+
309
+ toArray: function() {
310
+ return this.split('');
311
+ },
312
+
313
+ succ: function() {
314
+ return this.slice(0, this.length - 1) +
315
+ String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
316
+ },
317
+
318
+ times: function(count) {
319
+ var result = '';
320
+ for (var i = 0; i < count; i++) result += this;
321
+ return result;
322
+ },
323
+
324
+ camelize: function() {
325
+ var parts = this.split('-'), len = parts.length;
326
+ if (len == 1) return parts[0];
327
+
328
+ var camelized = this.charAt(0) == '-'
329
+ ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
330
+ : parts[0];
331
+
332
+ for (var i = 1; i < len; i++)
333
+ camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
334
+
335
+ return camelized;
336
+ },
337
+
338
+ capitalize: function() {
339
+ return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
340
+ },
341
+
342
+ underscore: function() {
343
+ return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
344
+ },
345
+
346
+ dasherize: function() {
347
+ return this.gsub(/_/,'-');
348
+ },
349
+
350
+ inspect: function(useDoubleQuotes) {
351
+ var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
352
+ var character = String.specialChar[match[0]];
353
+ return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
354
+ });
355
+ if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
356
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
357
+ },
358
+
359
+ toJSON: function() {
360
+ return this.inspect(true);
361
+ },
362
+
363
+ unfilterJSON: function(filter) {
364
+ return this.sub(filter || Prototype.JSONFilter, '#{1}');
365
+ },
366
+
367
+ isJSON: function() {
368
+ var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
369
+ return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
370
+ },
371
+
372
+ evalJSON: function(sanitize) {
373
+ var json = this.unfilterJSON();
374
+ try {
375
+ if (!sanitize || json.isJSON()) return eval('(' + json + ')');
376
+ } catch (e) { }
377
+ throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
378
+ },
379
+
380
+ include: function(pattern) {
381
+ return this.indexOf(pattern) > -1;
382
+ },
383
+
384
+ startsWith: function(pattern) {
385
+ return this.indexOf(pattern) === 0;
386
+ },
387
+
388
+ endsWith: function(pattern) {
389
+ var d = this.length - pattern.length;
390
+ return d >= 0 && this.lastIndexOf(pattern) === d;
391
+ },
392
+
393
+ empty: function() {
394
+ return this == '';
395
+ },
396
+
397
+ blank: function() {
398
+ return /^\s*$/.test(this);
399
+ }
400
+ });
401
+
402
+ if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
403
+ escapeHTML: function() {
404
+ return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
405
+ },
406
+ unescapeHTML: function() {
407
+ return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
408
+ }
409
+ });
410
+
411
+ String.prototype.gsub.prepareReplacement = function(replacement) {
412
+ if (typeof replacement == 'function') return replacement;
413
+ var template = new Template(replacement);
414
+ return function(match) { return template.evaluate(match) };
415
+ }
416
+
417
+ String.prototype.parseQuery = String.prototype.toQueryParams;
418
+
419
+ Object.extend(String.prototype.escapeHTML, {
420
+ div: document.createElement('div'),
421
+ text: document.createTextNode('')
422
+ });
423
+
424
+ with (String.prototype.escapeHTML) div.appendChild(text);
425
+
426
+ var Template = Class.create();
427
+ Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
428
+ Template.prototype = {
429
+ initialize: function(template, pattern) {
430
+ this.template = template.toString();
431
+ this.pattern = pattern || Template.Pattern;
432
+ },
433
+
434
+ evaluate: function(object) {
435
+ return this.template.gsub(this.pattern, function(match) {
436
+ var before = match[1];
437
+ if (before == '\\') return match[2];
438
+ return before + String.interpret(object[match[3]]);
439
+ });
440
+ }
441
+ }
442
+
443
+ var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');
444
+
445
+ var Enumerable = {
446
+ each: function(iterator) {
447
+ var index = 0;
448
+ try {
449
+ this._each(function(value) {
450
+ iterator(value, index++);
451
+ });
452
+ } catch (e) {
453
+ if (e != $break) throw e;
454
+ }
455
+ return this;
456
+ },
457
+
458
+ eachSlice: function(number, iterator) {
459
+ var index = -number, slices = [], array = this.toArray();
460
+ while ((index += number) < array.length)
461
+ slices.push(array.slice(index, index+number));
462
+ return slices.map(iterator);
463
+ },
464
+
465
+ all: function(iterator) {
466
+ var result = true;
467
+ this.each(function(value, index) {
468
+ result = result && !!(iterator || Prototype.K)(value, index);
469
+ if (!result) throw $break;
470
+ });
471
+ return result;
472
+ },
473
+
474
+ any: function(iterator) {
475
+ var result = false;
476
+ this.each(function(value, index) {
477
+ if (result = !!(iterator || Prototype.K)(value, index))
478
+ throw $break;
479
+ });
480
+ return result;
481
+ },
482
+
483
+ collect: function(iterator) {
484
+ var results = [];
485
+ this.each(function(value, index) {
486
+ results.push((iterator || Prototype.K)(value, index));
487
+ });
488
+ return results;
489
+ },
490
+
491
+ detect: function(iterator) {
492
+ var result;
493
+ this.each(function(value, index) {
494
+ if (iterator(value, index)) {
495
+ result = value;
496
+ throw $break;
497
+ }
498
+ });
499
+ return result;
500
+ },
501
+
502
+ findAll: function(iterator) {
503
+ var results = [];
504
+ this.each(function(value, index) {
505
+ if (iterator(value, index))
506
+ results.push(value);
507
+ });
508
+ return results;
509
+ },
510
+
511
+ grep: function(pattern, iterator) {
512
+ var results = [];
513
+ this.each(function(value, index) {
514
+ var stringValue = value.toString();
515
+ if (stringValue.match(pattern))
516
+ results.push((iterator || Prototype.K)(value, index));
517
+ })
518
+ return results;
519
+ },
520
+
521
+ include: function(object) {
522
+ var found = false;
523
+ this.each(function(value) {
524
+ if (value == object) {
525
+ found = true;
526
+ throw $break;
527
+ }
528
+ });
529
+ return found;
530
+ },
531
+
532
+ inGroupsOf: function(number, fillWith) {
533
+ fillWith = fillWith === undefined ? null : fillWith;
534
+ return this.eachSlice(number, function(slice) {
535
+ while(slice.length < number) slice.push(fillWith);
536
+ return slice;
537
+ });
538
+ },
539
+
540
+ inject: function(memo, iterator) {
541
+ this.each(function(value, index) {
542
+ memo = iterator(memo, value, index);
543
+ });
544
+ return memo;
545
+ },
546
+
547
+ invoke: function(method) {
548
+ var args = $A(arguments).slice(1);
549
+ return this.map(function(value) {
550
+ return value[method].apply(value, args);
551
+ });
552
+ },
553
+
554
+ max: function(iterator) {
555
+ var result;
556
+ this.each(function(value, index) {
557
+ value = (iterator || Prototype.K)(value, index);
558
+ if (result == undefined || value >= result)
559
+ result = value;
560
+ });
561
+ return result;
562
+ },
563
+
564
+ min: function(iterator) {
565
+ var result;
566
+ this.each(function(value, index) {
567
+ value = (iterator || Prototype.K)(value, index);
568
+ if (result == undefined || value < result)
569
+ result = value;
570
+ });
571
+ return result;
572
+ },
573
+
574
+ partition: function(iterator) {
575
+ var trues = [], falses = [];
576
+ this.each(function(value, index) {
577
+ ((iterator || Prototype.K)(value, index) ?
578
+ trues : falses).push(value);
579
+ });
580
+ return [trues, falses];
581
+ },
582
+
583
+ pluck: function(property) {
584
+ var results = [];
585
+ this.each(function(value, index) {
586
+ results.push(value[property]);
587
+ });
588
+ return results;
589
+ },
590
+
591
+ reject: function(iterator) {
592
+ var results = [];
593
+ this.each(function(value, index) {
594
+ if (!iterator(value, index))
595
+ results.push(value);
596
+ });
597
+ return results;
598
+ },
599
+
600
+ sortBy: function(iterator) {
601
+ return this.map(function(value, index) {
602
+ return {value: value, criteria: iterator(value, index)};
603
+ }).sort(function(left, right) {
604
+ var a = left.criteria, b = right.criteria;
605
+ return a < b ? -1 : a > b ? 1 : 0;
606
+ }).pluck('value');
607
+ },
608
+
609
+ toArray: function() {
610
+ return this.map();
611
+ },
612
+
613
+ zip: function() {
614
+ var iterator = Prototype.K, args = $A(arguments);
615
+ if (typeof args.last() == 'function')
616
+ iterator = args.pop();
617
+
618
+ var collections = [this].concat(args).map($A);
619
+ return this.map(function(value, index) {
620
+ return iterator(collections.pluck(index));
621
+ });
622
+ },
623
+
624
+ size: function() {
625
+ return this.toArray().length;
626
+ },
627
+
628
+ inspect: function() {
629
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
630
+ }
631
+ }
632
+
633
+ Object.extend(Enumerable, {
634
+ map: Enumerable.collect,
635
+ find: Enumerable.detect,
636
+ select: Enumerable.findAll,
637
+ member: Enumerable.include,
638
+ entries: Enumerable.toArray
639
+ });
640
+ var $A = Array.from = function(iterable) {
641
+ if (!iterable) return [];
642
+ if (iterable.toArray) {
643
+ return iterable.toArray();
644
+ } else {
645
+ var results = [];
646
+ for (var i = 0, length = iterable.length; i < length; i++)
647
+ results.push(iterable[i]);
648
+ return results;
649
+ }
650
+ }
651
+
652
+ if (Prototype.Browser.WebKit) {
653
+ $A = Array.from = function(iterable) {
654
+ if (!iterable) return [];
655
+ if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
656
+ iterable.toArray) {
657
+ return iterable.toArray();
658
+ } else {
659
+ var results = [];
660
+ for (var i = 0, length = iterable.length; i < length; i++)
661
+ results.push(iterable[i]);
662
+ return results;
663
+ }
664
+ }
665
+ }
666
+
667
+ Object.extend(Array.prototype, Enumerable);
668
+
669
+ if (!Array.prototype._reverse)
670
+ Array.prototype._reverse = Array.prototype.reverse;
671
+
672
+ Object.extend(Array.prototype, {
673
+ _each: function(iterator) {
674
+ for (var i = 0, length = this.length; i < length; i++)
675
+ iterator(this[i]);
676
+ },
677
+
678
+ clear: function() {
679
+ this.length = 0;
680
+ return this;
681
+ },
682
+
683
+ first: function() {
684
+ return this[0];
685
+ },
686
+
687
+ last: function() {
688
+ return this[this.length - 1];
689
+ },
690
+
691
+ compact: function() {
692
+ return this.select(function(value) {
693
+ return value != null;
694
+ });
695
+ },
696
+
697
+ flatten: function() {
698
+ return this.inject([], function(array, value) {
699
+ return array.concat(value && value.constructor == Array ?
700
+ value.flatten() : [value]);
701
+ });
702
+ },
703
+
704
+ without: function() {
705
+ var values = $A(arguments);
706
+ return this.select(function(value) {
707
+ return !values.include(value);
708
+ });
709
+ },
710
+
711
+ indexOf: function(object) {
712
+ for (var i = 0, length = this.length; i < length; i++)
713
+ if (this[i] == object) return i;
714
+ return -1;
715
+ },
716
+
717
+ reverse: function(inline) {
718
+ return (inline !== false ? this : this.toArray())._reverse();
719
+ },
720
+
721
+ reduce: function() {
722
+ return this.length > 1 ? this : this[0];
723
+ },
724
+
725
+ uniq: function(sorted) {
726
+ return this.inject([], function(array, value, index) {
727
+ if (0 == index || (sorted ? array.last() != value : !array.include(value)))
728
+ array.push(value);
729
+ return array;
730
+ });
731
+ },
732
+
733
+ clone: function() {
734
+ return [].concat(this);
735
+ },
736
+
737
+ size: function() {
738
+ return this.length;
739
+ },
740
+
741
+ inspect: function() {
742
+ return '[' + this.map(Object.inspect).join(', ') + ']';
743
+ },
744
+
745
+ toJSON: function() {
746
+ var results = [];
747
+ this.each(function(object) {
748
+ var value = Object.toJSON(object);
749
+ if (value !== undefined) results.push(value);
750
+ });
751
+ return '[' + results.join(', ') + ']';
752
+ }
753
+ });
754
+
755
+ Array.prototype.toArray = Array.prototype.clone;
756
+
757
+ function $w(string) {
758
+ string = string.strip();
759
+ return string ? string.split(/\s+/) : [];
760
+ }
761
+
762
+ if (Prototype.Browser.Opera){
763
+ Array.prototype.concat = function() {
764
+ var array = [];
765
+ for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
766
+ for (var i = 0, length = arguments.length; i < length; i++) {
767
+ if (arguments[i].constructor == Array) {
768
+ for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
769
+ array.push(arguments[i][j]);
770
+ } else {
771
+ array.push(arguments[i]);
772
+ }
773
+ }
774
+ return array;
775
+ }
776
+ }
777
+ var Hash = function(object) {
778
+ if (object instanceof Hash) this.merge(object);
779
+ else Object.extend(this, object || {});
780
+ };
781
+
782
+ Object.extend(Hash, {
783
+ toQueryString: function(obj) {
784
+ var parts = [];
785
+ parts.add = arguments.callee.addPair;
786
+
787
+ this.prototype._each.call(obj, function(pair) {
788
+ if (!pair.key) return;
789
+ var value = pair.value;
790
+
791
+ if (value && typeof value == 'object') {
792
+ if (value.constructor == Array) value.each(function(value) {
793
+ parts.add(pair.key, value);
794
+ });
795
+ return;
796
+ }
797
+ parts.add(pair.key, value);
798
+ });
799
+
800
+ return parts.join('&');
801
+ },
802
+
803
+ toJSON: function(object) {
804
+ var results = [];
805
+ this.prototype._each.call(object, function(pair) {
806
+ var value = Object.toJSON(pair.value);
807
+ if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
808
+ });
809
+ return '{' + results.join(', ') + '}';
810
+ }
811
+ });
812
+
813
+ Hash.toQueryString.addPair = function(key, value, prefix) {
814
+ key = encodeURIComponent(key);
815
+ if (value === undefined) this.push(key);
816
+ else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
817
+ }
818
+
819
+ Object.extend(Hash.prototype, Enumerable);
820
+ Object.extend(Hash.prototype, {
821
+ _each: function(iterator) {
822
+ for (var key in this) {
823
+ var value = this[key];
824
+ if (value && value == Hash.prototype[key]) continue;
825
+
826
+ var pair = [key, value];
827
+ pair.key = key;
828
+ pair.value = value;
829
+ iterator(pair);
830
+ }
831
+ },
832
+
833
+ keys: function() {
834
+ return this.pluck('key');
835
+ },
836
+
837
+ values: function() {
838
+ return this.pluck('value');
839
+ },
840
+
841
+ merge: function(hash) {
842
+ return $H(hash).inject(this, function(mergedHash, pair) {
843
+ mergedHash[pair.key] = pair.value;
844
+ return mergedHash;
845
+ });
846
+ },
847
+
848
+ remove: function() {
849
+ var result;
850
+ for(var i = 0, length = arguments.length; i < length; i++) {
851
+ var value = this[arguments[i]];
852
+ if (value !== undefined){
853
+ if (result === undefined) result = value;
854
+ else {
855
+ if (result.constructor != Array) result = [result];
856
+ result.push(value)
857
+ }
858
+ }
859
+ delete this[arguments[i]];
860
+ }
861
+ return result;
862
+ },
863
+
864
+ toQueryString: function() {
865
+ return Hash.toQueryString(this);
866
+ },
867
+
868
+ inspect: function() {
869
+ return '#<Hash:{' + this.map(function(pair) {
870
+ return pair.map(Object.inspect).join(': ');
871
+ }).join(', ') + '}>';
872
+ },
873
+
874
+ toJSON: function() {
875
+ return Hash.toJSON(this);
876
+ }
877
+ });
878
+
879
+ function $H(object) {
880
+ if (object instanceof Hash) return object;
881
+ return new Hash(object);
882
+ };
883
+
884
+ // Safari iterates over shadowed properties
885
+ if (function() {
886
+ var i = 0, Test = function(value) { this.key = value };
887
+ Test.prototype.key = 'foo';
888
+ for (var property in new Test('bar')) i++;
889
+ return i > 1;
890
+ }()) Hash.prototype._each = function(iterator) {
891
+ var cache = [];
892
+ for (var key in this) {
893
+ var value = this[key];
894
+ if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
895
+ cache.push(key);
896
+ var pair = [key, value];
897
+ pair.key = key;
898
+ pair.value = value;
899
+ iterator(pair);
900
+ }
901
+ };
902
+ ObjectRange = Class.create();
903
+ Object.extend(ObjectRange.prototype, Enumerable);
904
+ Object.extend(ObjectRange.prototype, {
905
+ initialize: function(start, end, exclusive) {
906
+ this.start = start;
907
+ this.end = end;
908
+ this.exclusive = exclusive;
909
+ },
910
+
911
+ _each: function(iterator) {
912
+ var value = this.start;
913
+ while (this.include(value)) {
914
+ iterator(value);
915
+ value = value.succ();
916
+ }
917
+ },
918
+
919
+ include: function(value) {
920
+ if (value < this.start)
921
+ return false;
922
+ if (this.exclusive)
923
+ return value < this.end;
924
+ return value <= this.end;
925
+ }
926
+ });
927
+
928
+ var $R = function(start, end, exclusive) {
929
+ return new ObjectRange(start, end, exclusive);
930
+ }
931
+
932
+ var Ajax = {
933
+ getTransport: function() {
934
+ return Try.these(
935
+ function() {return new XMLHttpRequest()},
936
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
937
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
938
+ ) || false;
939
+ },
940
+
941
+ activeRequestCount: 0
942
+ }
943
+
944
+ Ajax.Responders = {
945
+ responders: [],
946
+
947
+ _each: function(iterator) {
948
+ this.responders._each(iterator);
949
+ },
950
+
951
+ register: function(responder) {
952
+ if (!this.include(responder))
953
+ this.responders.push(responder);
954
+ },
955
+
956
+ unregister: function(responder) {
957
+ this.responders = this.responders.without(responder);
958
+ },
959
+
960
+ dispatch: function(callback, request, transport, json) {
961
+ this.each(function(responder) {
962
+ if (typeof responder[callback] == 'function') {
963
+ try {
964
+ responder[callback].apply(responder, [request, transport, json]);
965
+ } catch (e) {}
966
+ }
967
+ });
968
+ }
969
+ };
970
+
971
+ Object.extend(Ajax.Responders, Enumerable);
972
+
973
+ Ajax.Responders.register({
974
+ onCreate: function() {
975
+ Ajax.activeRequestCount++;
976
+ },
977
+ onComplete: function() {
978
+ Ajax.activeRequestCount--;
979
+ }
980
+ });
981
+
982
+ Ajax.Base = function() {};
983
+ Ajax.Base.prototype = {
984
+ setOptions: function(options) {
985
+ this.options = {
986
+ method: 'post',
987
+ asynchronous: true,
988
+ contentType: 'application/x-www-form-urlencoded',
989
+ encoding: 'UTF-8',
990
+ parameters: ''
991
+ }
992
+ Object.extend(this.options, options || {});
993
+
994
+ this.options.method = this.options.method.toLowerCase();
995
+ if (typeof this.options.parameters == 'string')
996
+ this.options.parameters = this.options.parameters.toQueryParams();
997
+ }
998
+ }
999
+
1000
+ Ajax.Request = Class.create();
1001
+ Ajax.Request.Events =
1002
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1003
+
1004
+ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
1005
+ _complete: false,
1006
+
1007
+ initialize: function(url, options) {
1008
+ this.transport = Ajax.getTransport();
1009
+ this.setOptions(options);
1010
+ this.request(url);
1011
+ },
1012
+
1013
+ request: function(url) {
1014
+ this.url = url;
1015
+ this.method = this.options.method;
1016
+ var params = Object.clone(this.options.parameters);
1017
+
1018
+ if (!['get', 'post'].include(this.method)) {
1019
+ // simulate other verbs over post
1020
+ params['_method'] = this.method;
1021
+ this.method = 'post';
1022
+ }
1023
+
1024
+ this.parameters = params;
1025
+
1026
+ if (params = Hash.toQueryString(params)) {
1027
+ // when GET, append parameters to URL
1028
+ if (this.method == 'get')
1029
+ this.url += (this.url.include('?') ? '&' : '?') + params;
1030
+ else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1031
+ params += '&_=';
1032
+ }
1033
+
1034
+ try {
1035
+ if (this.options.onCreate) this.options.onCreate(this.transport);
1036
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
1037
+
1038
+ this.transport.open(this.method.toUpperCase(), this.url,
1039
+ this.options.asynchronous);
1040
+
1041
+ if (this.options.asynchronous)
1042
+ setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
1043
+
1044
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
1045
+ this.setRequestHeaders();
1046
+
1047
+ this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1048
+ this.transport.send(this.body);
1049
+
1050
+ /* Force Firefox to handle ready state 4 for synchronous requests */
1051
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
1052
+ this.onStateChange();
1053
+
1054
+ }
1055
+ catch (e) {
1056
+ this.dispatchException(e);
1057
+ }
1058
+ },
1059
+
1060
+ onStateChange: function() {
1061
+ var readyState = this.transport.readyState;
1062
+ if (readyState > 1 && !((readyState == 4) && this._complete))
1063
+ this.respondToReadyState(this.transport.readyState);
1064
+ },
1065
+
1066
+ setRequestHeaders: function() {
1067
+ var headers = {
1068
+ 'X-Requested-With': 'XMLHttpRequest',
1069
+ 'X-Prototype-Version': Prototype.Version,
1070
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1071
+ };
1072
+
1073
+ if (this.method == 'post') {
1074
+ headers['Content-type'] = this.options.contentType +
1075
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
1076
+
1077
+ /* Force "Connection: close" for older Mozilla browsers to work
1078
+ * around a bug where XMLHttpRequest sends an incorrect
1079
+ * Content-length header. See Mozilla Bugzilla #246651.
1080
+ */
1081
+ if (this.transport.overrideMimeType &&
1082
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1083
+ headers['Connection'] = 'close';
1084
+ }
1085
+
1086
+ // user-defined headers
1087
+ if (typeof this.options.requestHeaders == 'object') {
1088
+ var extras = this.options.requestHeaders;
1089
+
1090
+ if (typeof extras.push == 'function')
1091
+ for (var i = 0, length = extras.length; i < length; i += 2)
1092
+ headers[extras[i]] = extras[i+1];
1093
+ else
1094
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1095
+ }
1096
+
1097
+ for (var name in headers)
1098
+ this.transport.setRequestHeader(name, headers[name]);
1099
+ },
1100
+
1101
+ success: function() {
1102
+ return !this.transport.status
1103
+ || (this.transport.status >= 200 && this.transport.status < 300);
1104
+ },
1105
+
1106
+ respondToReadyState: function(readyState) {
1107
+ var state = Ajax.Request.Events[readyState];
1108
+ var transport = this.transport, json = this.evalJSON();
1109
+
1110
+ if (state == 'Complete') {
1111
+ try {
1112
+ this._complete = true;
1113
+ (this.options['on' + this.transport.status]
1114
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1115
+ || Prototype.emptyFunction)(transport, json);
1116
+ } catch (e) {
1117
+ this.dispatchException(e);
1118
+ }
1119
+
1120
+ var contentType = this.getHeader('Content-type');
1121
+ if (contentType && contentType.strip().
1122
+ match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
1123
+ this.evalResponse();
1124
+ }
1125
+
1126
+ try {
1127
+ (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
1128
+ Ajax.Responders.dispatch('on' + state, this, transport, json);
1129
+ } catch (e) {
1130
+ this.dispatchException(e);
1131
+ }
1132
+
1133
+ if (state == 'Complete') {
1134
+ // avoid memory leak in MSIE: clean up
1135
+ this.transport.onreadystatechange = Prototype.emptyFunction;
1136
+ }
1137
+ },
1138
+
1139
+ getHeader: function(name) {
1140
+ try {
1141
+ return this.transport.getResponseHeader(name);
1142
+ } catch (e) { return null }
1143
+ },
1144
+
1145
+ evalJSON: function() {
1146
+ try {
1147
+ var json = this.getHeader('X-JSON');
1148
+ return json ? json.evalJSON() : null;
1149
+ } catch (e) { return null }
1150
+ },
1151
+
1152
+ evalResponse: function() {
1153
+ try {
1154
+ return eval((this.transport.responseText || '').unfilterJSON());
1155
+ } catch (e) {
1156
+ this.dispatchException(e);
1157
+ }
1158
+ },
1159
+
1160
+ dispatchException: function(exception) {
1161
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
1162
+ Ajax.Responders.dispatch('onException', this, exception);
1163
+ }
1164
+ });
1165
+
1166
+ Ajax.Updater = Class.create();
1167
+
1168
+ Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
1169
+ initialize: function(container, url, options) {
1170
+ this.container = {
1171
+ success: (container.success || container),
1172
+ failure: (container.failure || (container.success ? null : container))
1173
+ }
1174
+
1175
+ this.transport = Ajax.getTransport();
1176
+ this.setOptions(options);
1177
+
1178
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
1179
+ this.options.onComplete = (function(transport, param) {
1180
+ this.updateContent();
1181
+ onComplete(transport, param);
1182
+ }).bind(this);
1183
+
1184
+ this.request(url);
1185
+ },
1186
+
1187
+ updateContent: function() {
1188
+ var receiver = this.container[this.success() ? 'success' : 'failure'];
1189
+ var response = this.transport.responseText;
1190
+
1191
+ if (!this.options.evalScripts) response = response.stripScripts();
1192
+
1193
+ if (receiver = $(receiver)) {
1194
+ if (this.options.insertion)
1195
+ new this.options.insertion(receiver, response);
1196
+ else
1197
+ receiver.update(response);
1198
+ }
1199
+
1200
+ if (this.success()) {
1201
+ if (this.onComplete)
1202
+ setTimeout(this.onComplete.bind(this), 10);
1203
+ }
1204
+ }
1205
+ });
1206
+
1207
+ Ajax.PeriodicalUpdater = Class.create();
1208
+ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
1209
+ initialize: function(container, url, options) {
1210
+ this.setOptions(options);
1211
+ this.onComplete = this.options.onComplete;
1212
+
1213
+ this.frequency = (this.options.frequency || 2);
1214
+ this.decay = (this.options.decay || 1);
1215
+
1216
+ this.updater = {};
1217
+ this.container = container;
1218
+ this.url = url;
1219
+
1220
+ this.start();
1221
+ },
1222
+
1223
+ start: function() {
1224
+ this.options.onComplete = this.updateComplete.bind(this);
1225
+ this.onTimerEvent();
1226
+ },
1227
+
1228
+ stop: function() {
1229
+ this.updater.options.onComplete = undefined;
1230
+ clearTimeout(this.timer);
1231
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1232
+ },
1233
+
1234
+ updateComplete: function(request) {
1235
+ if (this.options.decay) {
1236
+ this.decay = (request.responseText == this.lastText ?
1237
+ this.decay * this.options.decay : 1);
1238
+
1239
+ this.lastText = request.responseText;
1240
+ }
1241
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
1242
+ this.decay * this.frequency * 1000);
1243
+ },
1244
+
1245
+ onTimerEvent: function() {
1246
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
1247
+ }
1248
+ });
1249
+ function $(element) {
1250
+ if (arguments.length > 1) {
1251
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
1252
+ elements.push($(arguments[i]));
1253
+ return elements;
1254
+ }
1255
+ if (typeof element == 'string')
1256
+ element = document.getElementById(element);
1257
+ return Element.extend(element);
1258
+ }
1259
+
1260
+ if (Prototype.BrowserFeatures.XPath) {
1261
+ document._getElementsByXPath = function(expression, parentElement) {
1262
+ var results = [];
1263
+ var query = document.evaluate(expression, $(parentElement) || document,
1264
+ null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1265
+ for (var i = 0, length = query.snapshotLength; i < length; i++)
1266
+ results.push(query.snapshotItem(i));
1267
+ return results;
1268
+ };
1269
+
1270
+ document.getElementsByClassName = function(className, parentElement) {
1271
+ var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
1272
+ return document._getElementsByXPath(q, parentElement);
1273
+ }
1274
+
1275
+ } else document.getElementsByClassName = function(className, parentElement) {
1276
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
1277
+ var elements = [], child, pattern = new RegExp("(^|\\s)" + className + "(\\s|$)");
1278
+ for (var i = 0, length = children.length; i < length; i++) {
1279
+ child = children[i];
1280
+ var elementClassName = child.className;
1281
+ if (elementClassName.length == 0) continue;
1282
+ if (elementClassName == className || elementClassName.match(pattern))
1283
+ elements.push(Element.extend(child));
1284
+ }
1285
+ return elements;
1286
+ };
1287
+
1288
+ /*--------------------------------------------------------------------------*/
1289
+
1290
+ if (!window.Element) var Element = {};
1291
+
1292
+ Element.extend = function(element) {
1293
+ var F = Prototype.BrowserFeatures;
1294
+ if (!element || !element.tagName || element.nodeType == 3 ||
1295
+ element._extended || F.SpecificElementExtensions || element == window)
1296
+ return element;
1297
+
1298
+ var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
1299
+ T = Element.Methods.ByTag;
1300
+
1301
+ // extend methods for all tags (Safari doesn't need this)
1302
+ if (!F.ElementExtensions) {
1303
+ Object.extend(methods, Element.Methods),
1304
+ Object.extend(methods, Element.Methods.Simulated);
1305
+ }
1306
+
1307
+ // extend methods for specific tags
1308
+ if (T[tagName]) Object.extend(methods, T[tagName]);
1309
+
1310
+ for (var property in methods) {
1311
+ var value = methods[property];
1312
+ if (typeof value == 'function' && !(property in element))
1313
+ element[property] = cache.findOrStore(value);
1314
+ }
1315
+
1316
+ element._extended = Prototype.emptyFunction;
1317
+ return element;
1318
+ };
1319
+
1320
+ Element.extend.cache = {
1321
+ findOrStore: function(value) {
1322
+ return this[value] = this[value] || function() {
1323
+ return value.apply(null, [this].concat($A(arguments)));
1324
+ }
1325
+ }
1326
+ };
1327
+
1328
+ Element.Methods = {
1329
+ visible: function(element) {
1330
+ return $(element).style.display != 'none';
1331
+ },
1332
+
1333
+ toggle: function(element) {
1334
+ element = $(element);
1335
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
1336
+ return element;
1337
+ },
1338
+
1339
+ hide: function(element) {
1340
+ $(element).style.display = 'none';
1341
+ return element;
1342
+ },
1343
+
1344
+ show: function(element) {
1345
+ $(element).style.display = '';
1346
+ return element;
1347
+ },
1348
+
1349
+ remove: function(element) {
1350
+ element = $(element);
1351
+ element.parentNode.removeChild(element);
1352
+ return element;
1353
+ },
1354
+
1355
+ update: function(element, html) {
1356
+ html = typeof html == 'undefined' ? '' : html.toString();
1357
+ $(element).innerHTML = html.stripScripts();
1358
+ setTimeout(function() {html.evalScripts()}, 10);
1359
+ return element;
1360
+ },
1361
+
1362
+ replace: function(element, html) {
1363
+ element = $(element);
1364
+ html = typeof html == 'undefined' ? '' : html.toString();
1365
+ if (element.outerHTML) {
1366
+ element.outerHTML = html.stripScripts();
1367
+ } else {
1368
+ var range = element.ownerDocument.createRange();
1369
+ range.selectNodeContents(element);
1370
+ element.parentNode.replaceChild(
1371
+ range.createContextualFragment(html.stripScripts()), element);
1372
+ }
1373
+ setTimeout(function() {html.evalScripts()}, 10);
1374
+ return element;
1375
+ },
1376
+
1377
+ inspect: function(element) {
1378
+ element = $(element);
1379
+ var result = '<' + element.tagName.toLowerCase();
1380
+ $H({'id': 'id', 'className': 'class'}).each(function(pair) {
1381
+ var property = pair.first(), attribute = pair.last();
1382
+ var value = (element[property] || '').toString();
1383
+ if (value) result += ' ' + attribute + '=' + value.inspect(true);
1384
+ });
1385
+ return result + '>';
1386
+ },
1387
+
1388
+ recursivelyCollect: function(element, property) {
1389
+ element = $(element);
1390
+ var elements = [];
1391
+ while (element = element[property])
1392
+ if (element.nodeType == 1)
1393
+ elements.push(Element.extend(element));
1394
+ return elements;
1395
+ },
1396
+
1397
+ ancestors: function(element) {
1398
+ return $(element).recursivelyCollect('parentNode');
1399
+ },
1400
+
1401
+ descendants: function(element) {
1402
+ return $A($(element).getElementsByTagName('*')).each(Element.extend);
1403
+ },
1404
+
1405
+ firstDescendant: function(element) {
1406
+ element = $(element).firstChild;
1407
+ while (element && element.nodeType != 1) element = element.nextSibling;
1408
+ return $(element);
1409
+ },
1410
+
1411
+ immediateDescendants: function(element) {
1412
+ if (!(element = $(element).firstChild)) return [];
1413
+ while (element && element.nodeType != 1) element = element.nextSibling;
1414
+ if (element) return [element].concat($(element).nextSiblings());
1415
+ return [];
1416
+ },
1417
+
1418
+ previousSiblings: function(element) {
1419
+ return $(element).recursivelyCollect('previousSibling');
1420
+ },
1421
+
1422
+ nextSiblings: function(element) {
1423
+ return $(element).recursivelyCollect('nextSibling');
1424
+ },
1425
+
1426
+ siblings: function(element) {
1427
+ element = $(element);
1428
+ return element.previousSiblings().reverse().concat(element.nextSiblings());
1429
+ },
1430
+
1431
+ match: function(element, selector) {
1432
+ if (typeof selector == 'string')
1433
+ selector = new Selector(selector);
1434
+ return selector.match($(element));
1435
+ },
1436
+
1437
+ up: function(element, expression, index) {
1438
+ element = $(element);
1439
+ if (arguments.length == 1) return $(element.parentNode);
1440
+ var ancestors = element.ancestors();
1441
+ return expression ? Selector.findElement(ancestors, expression, index) :
1442
+ ancestors[index || 0];
1443
+ },
1444
+
1445
+ down: function(element, expression, index) {
1446
+ element = $(element);
1447
+ if (arguments.length == 1) return element.firstDescendant();
1448
+ var descendants = element.descendants();
1449
+ return expression ? Selector.findElement(descendants, expression, index) :
1450
+ descendants[index || 0];
1451
+ },
1452
+
1453
+ previous: function(element, expression, index) {
1454
+ element = $(element);
1455
+ if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1456
+ var previousSiblings = element.previousSiblings();
1457
+ return expression ? Selector.findElement(previousSiblings, expression, index) :
1458
+ previousSiblings[index || 0];
1459
+ },
1460
+
1461
+ next: function(element, expression, index) {
1462
+ element = $(element);
1463
+ if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1464
+ var nextSiblings = element.nextSiblings();
1465
+ return expression ? Selector.findElement(nextSiblings, expression, index) :
1466
+ nextSiblings[index || 0];
1467
+ },
1468
+
1469
+ getElementsBySelector: function() {
1470
+ var args = $A(arguments), element = $(args.shift());
1471
+ return Selector.findChildElements(element, args);
1472
+ },
1473
+
1474
+ getElementsByClassName: function(element, className) {
1475
+ return document.getElementsByClassName(className, element);
1476
+ },
1477
+
1478
+ readAttribute: function(element, name) {
1479
+ element = $(element);
1480
+ if (Prototype.Browser.IE) {
1481
+ if (!element.attributes) return null;
1482
+ var t = Element._attributeTranslations;
1483
+ if (t.values[name]) return t.values[name](element, name);
1484
+ if (t.names[name]) name = t.names[name];
1485
+ var attribute = element.attributes[name];
1486
+ return attribute ? attribute.nodeValue : null;
1487
+ }
1488
+ return element.getAttribute(name);
1489
+ },
1490
+
1491
+ getHeight: function(element) {
1492
+ return $(element).getDimensions().height;
1493
+ },
1494
+
1495
+ getWidth: function(element) {
1496
+ return $(element).getDimensions().width;
1497
+ },
1498
+
1499
+ classNames: function(element) {
1500
+ return new Element.ClassNames(element);
1501
+ },
1502
+
1503
+ hasClassName: function(element, className) {
1504
+ if (!(element = $(element))) return;
1505
+ var elementClassName = element.className;
1506
+ if (elementClassName.length == 0) return false;
1507
+ if (elementClassName == className ||
1508
+ elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
1509
+ return true;
1510
+ return false;
1511
+ },
1512
+
1513
+ addClassName: function(element, className) {
1514
+ if (!(element = $(element))) return;
1515
+ Element.classNames(element).add(className);
1516
+ return element;
1517
+ },
1518
+
1519
+ removeClassName: function(element, className) {
1520
+ if (!(element = $(element))) return;
1521
+ Element.classNames(element).remove(className);
1522
+ return element;
1523
+ },
1524
+
1525
+ toggleClassName: function(element, className) {
1526
+ if (!(element = $(element))) return;
1527
+ Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
1528
+ return element;
1529
+ },
1530
+
1531
+ observe: function() {
1532
+ Event.observe.apply(Event, arguments);
1533
+ return $A(arguments).first();
1534
+ },
1535
+
1536
+ stopObserving: function() {
1537
+ Event.stopObserving.apply(Event, arguments);
1538
+ return $A(arguments).first();
1539
+ },
1540
+
1541
+ // removes whitespace-only text node children
1542
+ cleanWhitespace: function(element) {
1543
+ element = $(element);
1544
+ var node = element.firstChild;
1545
+ while (node) {
1546
+ var nextNode = node.nextSibling;
1547
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
1548
+ element.removeChild(node);
1549
+ node = nextNode;
1550
+ }
1551
+ return element;
1552
+ },
1553
+
1554
+ empty: function(element) {
1555
+ return $(element).innerHTML.blank();
1556
+ },
1557
+
1558
+ descendantOf: function(element, ancestor) {
1559
+ element = $(element), ancestor = $(ancestor);
1560
+ while (element = element.parentNode)
1561
+ if (element == ancestor) return true;
1562
+ return false;
1563
+ },
1564
+
1565
+ scrollTo: function(element) {
1566
+ element = $(element);
1567
+ var pos = Position.cumulativeOffset(element);
1568
+ window.scrollTo(pos[0], pos[1]);
1569
+ return element;
1570
+ },
1571
+
1572
+ getStyle: function(element, style) {
1573
+ element = $(element);
1574
+ style = style == 'float' ? 'cssFloat' : style.camelize();
1575
+ var value = element.style[style];
1576
+ if (!value) {
1577
+ var css = document.defaultView.getComputedStyle(element, null);
1578
+ value = css ? css[style] : null;
1579
+ }
1580
+ if (style == 'opacity') return value ? parseFloat(value) : 1.0;
1581
+ return value == 'auto' ? null : value;
1582
+ },
1583
+
1584
+ getOpacity: function(element) {
1585
+ return $(element).getStyle('opacity');
1586
+ },
1587
+
1588
+ setStyle: function(element, styles, camelized) {
1589
+ element = $(element);
1590
+ var elementStyle = element.style;
1591
+
1592
+ for (var property in styles)
1593
+ if (property == 'opacity') element.setOpacity(styles[property])
1594
+ else
1595
+ elementStyle[(property == 'float' || property == 'cssFloat') ?
1596
+ (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
1597
+ (camelized ? property : property.camelize())] = styles[property];
1598
+
1599
+ return element;
1600
+ },
1601
+
1602
+ setOpacity: function(element, value) {
1603
+ element = $(element);
1604
+ element.style.opacity = (value == 1 || value === '') ? '' :
1605
+ (value < 0.00001) ? 0 : value;
1606
+ return element;
1607
+ },
1608
+
1609
+ getDimensions: function(element) {
1610
+ element = $(element);
1611
+ var display = $(element).getStyle('display');
1612
+ if (display != 'none' && display != null) // Safari bug
1613
+ return {width: element.offsetWidth, height: element.offsetHeight};
1614
+
1615
+ // All *Width and *Height properties give 0 on elements with display none,
1616
+ // so enable the element temporarily
1617
+ var els = element.style;
1618
+ var originalVisibility = els.visibility;
1619
+ var originalPosition = els.position;
1620
+ var originalDisplay = els.display;
1621
+ els.visibility = 'hidden';
1622
+ els.position = 'absolute';
1623
+ els.display = 'block';
1624
+ var originalWidth = element.clientWidth;
1625
+ var originalHeight = element.clientHeight;
1626
+ els.display = originalDisplay;
1627
+ els.position = originalPosition;
1628
+ els.visibility = originalVisibility;
1629
+ return {width: originalWidth, height: originalHeight};
1630
+ },
1631
+
1632
+ makePositioned: function(element) {
1633
+ element = $(element);
1634
+ var pos = Element.getStyle(element, 'position');
1635
+ if (pos == 'static' || !pos) {
1636
+ element._madePositioned = true;
1637
+ element.style.position = 'relative';
1638
+ // Opera returns the offset relative to the positioning context, when an
1639
+ // element is position relative but top and left have not been defined
1640
+ if (window.opera) {
1641
+ element.style.top = 0;
1642
+ element.style.left = 0;
1643
+ }
1644
+ }
1645
+ return element;
1646
+ },
1647
+
1648
+ undoPositioned: function(element) {
1649
+ element = $(element);
1650
+ if (element._madePositioned) {
1651
+ element._madePositioned = undefined;
1652
+ element.style.position =
1653
+ element.style.top =
1654
+ element.style.left =
1655
+ element.style.bottom =
1656
+ element.style.right = '';
1657
+ }
1658
+ return element;
1659
+ },
1660
+
1661
+ makeClipping: function(element) {
1662
+ element = $(element);
1663
+ if (element._overflow) return element;
1664
+ element._overflow = element.style.overflow || 'auto';
1665
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1666
+ element.style.overflow = 'hidden';
1667
+ return element;
1668
+ },
1669
+
1670
+ undoClipping: function(element) {
1671
+ element = $(element);
1672
+ if (!element._overflow) return element;
1673
+ element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
1674
+ element._overflow = null;
1675
+ return element;
1676
+ }
1677
+ };
1678
+
1679
+ Object.extend(Element.Methods, {
1680
+ childOf: Element.Methods.descendantOf,
1681
+ childElements: Element.Methods.immediateDescendants
1682
+ });
1683
+
1684
+ if (Prototype.Browser.Opera) {
1685
+ Element.Methods._getStyle = Element.Methods.getStyle;
1686
+ Element.Methods.getStyle = function(element, style) {
1687
+ switch(style) {
1688
+ case 'left':
1689
+ case 'top':
1690
+ case 'right':
1691
+ case 'bottom':
1692
+ if (Element._getStyle(element, 'position') == 'static') return null;
1693
+ default: return Element._getStyle(element, style);
1694
+ }
1695
+ };
1696
+ }
1697
+ else if (Prototype.Browser.IE) {
1698
+ Element.Methods.getStyle = function(element, style) {
1699
+ element = $(element);
1700
+ style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
1701
+ var value = element.style[style];
1702
+ if (!value && element.currentStyle) value = element.currentStyle[style];
1703
+
1704
+ if (style == 'opacity') {
1705
+ if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
1706
+ if (value[1]) return parseFloat(value[1]) / 100;
1707
+ return 1.0;
1708
+ }
1709
+
1710
+ if (value == 'auto') {
1711
+ if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
1712
+ return element['offset'+style.capitalize()] + 'px';
1713
+ return null;
1714
+ }
1715
+ return value;
1716
+ };
1717
+
1718
+ Element.Methods.setOpacity = function(element, value) {
1719
+ element = $(element);
1720
+ var filter = element.getStyle('filter'), style = element.style;
1721
+ if (value == 1 || value === '') {
1722
+ style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
1723
+ return element;
1724
+ } else if (value < 0.00001) value = 0;
1725
+ style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
1726
+ 'alpha(opacity=' + (value * 100) + ')';
1727
+ return element;
1728
+ };
1729
+
1730
+ // IE is missing .innerHTML support for TABLE-related elements
1731
+ Element.Methods.update = function(element, html) {
1732
+ element = $(element);
1733
+ html = typeof html == 'undefined' ? '' : html.toString();
1734
+ var tagName = element.tagName.toUpperCase();
1735
+ if (['THEAD','TBODY','TR','TD'].include(tagName)) {
1736
+ var div = document.createElement('div');
1737
+ switch (tagName) {
1738
+ case 'THEAD':
1739
+ case 'TBODY':
1740
+ div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
1741
+ depth = 2;
1742
+ break;
1743
+ case 'TR':
1744
+ div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
1745
+ depth = 3;
1746
+ break;
1747
+ case 'TD':
1748
+ div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
1749
+ depth = 4;
1750
+ }
1751
+ $A(element.childNodes).each(function(node) { element.removeChild(node) });
1752
+ depth.times(function() { div = div.firstChild });
1753
+ $A(div.childNodes).each(function(node) { element.appendChild(node) });
1754
+ } else {
1755
+ element.innerHTML = html.stripScripts();
1756
+ }
1757
+ setTimeout(function() { html.evalScripts() }, 10);
1758
+ return element;
1759
+ }
1760
+ }
1761
+ else if (Prototype.Browser.Gecko) {
1762
+ Element.Methods.setOpacity = function(element, value) {
1763
+ element = $(element);
1764
+ element.style.opacity = (value == 1) ? 0.999999 :
1765
+ (value === '') ? '' : (value < 0.00001) ? 0 : value;
1766
+ return element;
1767
+ };
1768
+ }
1769
+
1770
+ Element._attributeTranslations = {
1771
+ names: {
1772
+ colspan: "colSpan",
1773
+ rowspan: "rowSpan",
1774
+ valign: "vAlign",
1775
+ datetime: "dateTime",
1776
+ accesskey: "accessKey",
1777
+ tabindex: "tabIndex",
1778
+ enctype: "encType",
1779
+ maxlength: "maxLength",
1780
+ readonly: "readOnly",
1781
+ longdesc: "longDesc"
1782
+ },
1783
+ values: {
1784
+ _getAttr: function(element, attribute) {
1785
+ return element.getAttribute(attribute, 2);
1786
+ },
1787
+ _flag: function(element, attribute) {
1788
+ return $(element).hasAttribute(attribute) ? attribute : null;
1789
+ },
1790
+ style: function(element) {
1791
+ return element.style.cssText.toLowerCase();
1792
+ },
1793
+ title: function(element) {
1794
+ var node = element.getAttributeNode('title');
1795
+ return node.specified ? node.nodeValue : null;
1796
+ }
1797
+ }
1798
+ };
1799
+
1800
+ (function() {
1801
+ Object.extend(this, {
1802
+ href: this._getAttr,
1803
+ src: this._getAttr,
1804
+ type: this._getAttr,
1805
+ disabled: this._flag,
1806
+ checked: this._flag,
1807
+ readonly: this._flag,
1808
+ multiple: this._flag
1809
+ });
1810
+ }).call(Element._attributeTranslations.values);
1811
+
1812
+ Element.Methods.Simulated = {
1813
+ hasAttribute: function(element, attribute) {
1814
+ var t = Element._attributeTranslations, node;
1815
+ attribute = t.names[attribute] || attribute;
1816
+ node = $(element).getAttributeNode(attribute);
1817
+ return node && node.specified;
1818
+ }
1819
+ };
1820
+
1821
+ Element.Methods.ByTag = {};
1822
+
1823
+ Object.extend(Element, Element.Methods);
1824
+
1825
+ if (!Prototype.BrowserFeatures.ElementExtensions &&
1826
+ document.createElement('div').__proto__) {
1827
+ window.HTMLElement = {};
1828
+ window.HTMLElement.prototype = document.createElement('div').__proto__;
1829
+ Prototype.BrowserFeatures.ElementExtensions = true;
1830
+ }
1831
+
1832
+ Element.hasAttribute = function(element, attribute) {
1833
+ if (element.hasAttribute) return element.hasAttribute(attribute);
1834
+ return Element.Methods.Simulated.hasAttribute(element, attribute);
1835
+ };
1836
+
1837
+ Element.addMethods = function(methods) {
1838
+ var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
1839
+
1840
+ if (!methods) {
1841
+ Object.extend(Form, Form.Methods);
1842
+ Object.extend(Form.Element, Form.Element.Methods);
1843
+ Object.extend(Element.Methods.ByTag, {
1844
+ "FORM": Object.clone(Form.Methods),
1845
+ "INPUT": Object.clone(Form.Element.Methods),
1846
+ "SELECT": Object.clone(Form.Element.Methods),
1847
+ "TEXTAREA": Object.clone(Form.Element.Methods)
1848
+ });
1849
+ }
1850
+
1851
+ if (arguments.length == 2) {
1852
+ var tagName = methods;
1853
+ methods = arguments[1];
1854
+ }
1855
+
1856
+ if (!tagName) Object.extend(Element.Methods, methods || {});
1857
+ else {
1858
+ if (tagName.constructor == Array) tagName.each(extend);
1859
+ else extend(tagName);
1860
+ }
1861
+
1862
+ function extend(tagName) {
1863
+ tagName = tagName.toUpperCase();
1864
+ if (!Element.Methods.ByTag[tagName])
1865
+ Element.Methods.ByTag[tagName] = {};
1866
+ Object.extend(Element.Methods.ByTag[tagName], methods);
1867
+ }
1868
+
1869
+ function copy(methods, destination, onlyIfAbsent) {
1870
+ onlyIfAbsent = onlyIfAbsent || false;
1871
+ var cache = Element.extend.cache;
1872
+ for (var property in methods) {
1873
+ var value = methods[property];
1874
+ if (!onlyIfAbsent || !(property in destination))
1875
+ destination[property] = cache.findOrStore(value);
1876
+ }
1877
+ }
1878
+
1879
+ function findDOMClass(tagName) {
1880
+ var klass;
1881
+ var trans = {
1882
+ "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
1883
+ "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
1884
+ "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
1885
+ "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
1886
+ "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
1887
+ "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
1888
+ "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
1889
+ "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
1890
+ "FrameSet", "IFRAME": "IFrame"
1891
+ };
1892
+ if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
1893
+ if (window[klass]) return window[klass];
1894
+ klass = 'HTML' + tagName + 'Element';
1895
+ if (window[klass]) return window[klass];
1896
+ klass = 'HTML' + tagName.capitalize() + 'Element';
1897
+ if (window[klass]) return window[klass];
1898
+
1899
+ window[klass] = {};
1900
+ window[klass].prototype = document.createElement(tagName).__proto__;
1901
+ return window[klass];
1902
+ }
1903
+
1904
+ if (F.ElementExtensions) {
1905
+ copy(Element.Methods, HTMLElement.prototype);
1906
+ copy(Element.Methods.Simulated, HTMLElement.prototype, true);
1907
+ }
1908
+
1909
+ if (F.SpecificElementExtensions) {
1910
+ for (var tag in Element.Methods.ByTag) {
1911
+ var klass = findDOMClass(tag);
1912
+ if (typeof klass == "undefined") continue;
1913
+ copy(T[tag], klass.prototype);
1914
+ }
1915
+ }
1916
+
1917
+ Object.extend(Element, Element.Methods);
1918
+ delete Element.ByTag;
1919
+ };
1920
+
1921
+ var Toggle = { display: Element.toggle };
1922
+
1923
+ /*--------------------------------------------------------------------------*/
1924
+
1925
+ Abstract.Insertion = function(adjacency) {
1926
+ this.adjacency = adjacency;
1927
+ }
1928
+
1929
+ Abstract.Insertion.prototype = {
1930
+ initialize: function(element, content) {
1931
+ this.element = $(element);
1932
+ this.content = content.stripScripts();
1933
+
1934
+ if (this.adjacency && this.element.insertAdjacentHTML) {
1935
+ try {
1936
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
1937
+ } catch (e) {
1938
+ var tagName = this.element.tagName.toUpperCase();
1939
+ if (['TBODY', 'TR'].include(tagName)) {
1940
+ this.insertContent(this.contentFromAnonymousTable());
1941
+ } else {
1942
+ throw e;
1943
+ }
1944
+ }
1945
+ } else {
1946
+ this.range = this.element.ownerDocument.createRange();
1947
+ if (this.initializeRange) this.initializeRange();
1948
+ this.insertContent([this.range.createContextualFragment(this.content)]);
1949
+ }
1950
+
1951
+ setTimeout(function() {content.evalScripts()}, 10);
1952
+ },
1953
+
1954
+ contentFromAnonymousTable: function() {
1955
+ var div = document.createElement('div');
1956
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
1957
+ return $A(div.childNodes[0].childNodes[0].childNodes);
1958
+ }
1959
+ }
1960
+
1961
+ var Insertion = new Object();
1962
+
1963
+ Insertion.Before = Class.create();
1964
+ Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
1965
+ initializeRange: function() {
1966
+ this.range.setStartBefore(this.element);
1967
+ },
1968
+
1969
+ insertContent: function(fragments) {
1970
+ fragments.each((function(fragment) {
1971
+ this.element.parentNode.insertBefore(fragment, this.element);
1972
+ }).bind(this));
1973
+ }
1974
+ });
1975
+
1976
+ Insertion.Top = Class.create();
1977
+ Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
1978
+ initializeRange: function() {
1979
+ this.range.selectNodeContents(this.element);
1980
+ this.range.collapse(true);
1981
+ },
1982
+
1983
+ insertContent: function(fragments) {
1984
+ fragments.reverse(false).each((function(fragment) {
1985
+ this.element.insertBefore(fragment, this.element.firstChild);
1986
+ }).bind(this));
1987
+ }
1988
+ });
1989
+
1990
+ Insertion.Bottom = Class.create();
1991
+ Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
1992
+ initializeRange: function() {
1993
+ this.range.selectNodeContents(this.element);
1994
+ this.range.collapse(this.element);
1995
+ },
1996
+
1997
+ insertContent: function(fragments) {
1998
+ fragments.each((function(fragment) {
1999
+ this.element.appendChild(fragment);
2000
+ }).bind(this));
2001
+ }
2002
+ });
2003
+
2004
+ Insertion.After = Class.create();
2005
+ Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
2006
+ initializeRange: function() {
2007
+ this.range.setStartAfter(this.element);
2008
+ },
2009
+
2010
+ insertContent: function(fragments) {
2011
+ fragments.each((function(fragment) {
2012
+ this.element.parentNode.insertBefore(fragment,
2013
+ this.element.nextSibling);
2014
+ }).bind(this));
2015
+ }
2016
+ });
2017
+
2018
+ /*--------------------------------------------------------------------------*/
2019
+
2020
+ Element.ClassNames = Class.create();
2021
+ Element.ClassNames.prototype = {
2022
+ initialize: function(element) {
2023
+ this.element = $(element);
2024
+ },
2025
+
2026
+ _each: function(iterator) {
2027
+ this.element.className.split(/\s+/).select(function(name) {
2028
+ return name.length > 0;
2029
+ })._each(iterator);
2030
+ },
2031
+
2032
+ set: function(className) {
2033
+ this.element.className = className;
2034
+ },
2035
+
2036
+ add: function(classNameToAdd) {
2037
+ if (this.include(classNameToAdd)) return;
2038
+ this.set($A(this).concat(classNameToAdd).join(' '));
2039
+ },
2040
+
2041
+ remove: function(classNameToRemove) {
2042
+ if (!this.include(classNameToRemove)) return;
2043
+ this.set($A(this).without(classNameToRemove).join(' '));
2044
+ },
2045
+
2046
+ toString: function() {
2047
+ return $A(this).join(' ');
2048
+ }
2049
+ };
2050
+
2051
+ Object.extend(Element.ClassNames.prototype, Enumerable);
2052
+ /* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
2053
+ * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2054
+ * license. Please see http://www.yui-ext.com/ for more information. */
2055
+
2056
+ var Selector = Class.create();
2057
+
2058
+ Selector.prototype = {
2059
+ initialize: function(expression) {
2060
+ this.expression = expression.strip();
2061
+ this.compileMatcher();
2062
+ },
2063
+
2064
+ compileMatcher: function() {
2065
+ // Selectors with namespaced attributes can't use the XPath version
2066
+ if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
2067
+ return this.compileXPathMatcher();
2068
+
2069
+ var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2070
+ c = Selector.criteria, le, p, m;
2071
+
2072
+ if (Selector._cache[e]) {
2073
+ this.matcher = Selector._cache[e]; return;
2074
+ }
2075
+ this.matcher = ["this.matcher = function(root) {",
2076
+ "var r = root, h = Selector.handlers, c = false, n;"];
2077
+
2078
+ while (e && le != e && (/\S/).test(e)) {
2079
+ le = e;
2080
+ for (var i in ps) {
2081
+ p = ps[i];
2082
+ if (m = e.match(p)) {
2083
+ this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
2084
+ new Template(c[i]).evaluate(m));
2085
+ e = e.replace(m[0], '');
2086
+ break;
2087
+ }
2088
+ }
2089
+ }
2090
+
2091
+ this.matcher.push("return h.unique(n);\n}");
2092
+ eval(this.matcher.join('\n'));
2093
+ Selector._cache[this.expression] = this.matcher;
2094
+ },
2095
+
2096
+ compileXPathMatcher: function() {
2097
+ var e = this.expression, ps = Selector.patterns,
2098
+ x = Selector.xpath, le, m;
2099
+
2100
+ if (Selector._cache[e]) {
2101
+ this.xpath = Selector._cache[e]; return;
2102
+ }
2103
+
2104
+ this.matcher = ['.//*'];
2105
+ while (e && le != e && (/\S/).test(e)) {
2106
+ le = e;
2107
+ for (var i in ps) {
2108
+ if (m = e.match(ps[i])) {
2109
+ this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
2110
+ new Template(x[i]).evaluate(m));
2111
+ e = e.replace(m[0], '');
2112
+ break;
2113
+ }
2114
+ }
2115
+ }
2116
+
2117
+ this.xpath = this.matcher.join('');
2118
+ Selector._cache[this.expression] = this.xpath;
2119
+ },
2120
+
2121
+ findElements: function(root) {
2122
+ root = root || document;
2123
+ if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2124
+ return this.matcher(root);
2125
+ },
2126
+
2127
+ match: function(element) {
2128
+ return this.findElements(document).include(element);
2129
+ },
2130
+
2131
+ toString: function() {
2132
+ return this.expression;
2133
+ },
2134
+
2135
+ inspect: function() {
2136
+ return "#<Selector:" + this.expression.inspect() + ">";
2137
+ }
2138
+ };
2139
+
2140
+ Object.extend(Selector, {
2141
+ _cache: {},
2142
+
2143
+ xpath: {
2144
+ descendant: "//*",
2145
+ child: "/*",
2146
+ adjacent: "/following-sibling::*[1]",
2147
+ laterSibling: '/following-sibling::*',
2148
+ tagName: function(m) {
2149
+ if (m[1] == '*') return '';
2150
+ return "[local-name()='" + m[1].toLowerCase() +
2151
+ "' or local-name()='" + m[1].toUpperCase() + "']";
2152
+ },
2153
+ className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
2154
+ id: "[@id='#{1}']",
2155
+ attrPresence: "[@#{1}]",
2156
+ attr: function(m) {
2157
+ m[3] = m[5] || m[6];
2158
+ return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
2159
+ },
2160
+ pseudo: function(m) {
2161
+ var h = Selector.xpath.pseudos[m[1]];
2162
+ if (!h) return '';
2163
+ if (typeof h === 'function') return h(m);
2164
+ return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
2165
+ },
2166
+ operators: {
2167
+ '=': "[@#{1}='#{3}']",
2168
+ '!=': "[@#{1}!='#{3}']",
2169
+ '^=': "[starts-with(@#{1}, '#{3}')]",
2170
+ '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
2171
+ '*=': "[contains(@#{1}, '#{3}')]",
2172
+ '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
2173
+ '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
2174
+ },
2175
+ pseudos: {
2176
+ 'first-child': '[not(preceding-sibling::*)]',
2177
+ 'last-child': '[not(following-sibling::*)]',
2178
+ 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2179
+ 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2180
+ 'checked': "[@checked]",
2181
+ 'disabled': "[@disabled]",
2182
+ 'enabled': "[not(@disabled)]",
2183
+ 'not': function(m) {
2184
+ var e = m[6], p = Selector.patterns,
2185
+ x = Selector.xpath, le, m, v;
2186
+
2187
+ var exclusion = [];
2188
+ while (e && le != e && (/\S/).test(e)) {
2189
+ le = e;
2190
+ for (var i in p) {
2191
+ if (m = e.match(p[i])) {
2192
+ v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
2193
+ exclusion.push("(" + v.substring(1, v.length - 1) + ")");
2194
+ e = e.replace(m[0], '');
2195
+ break;
2196
+ }
2197
+ }
2198
+ }
2199
+ return "[not(" + exclusion.join(" and ") + ")]";
2200
+ },
2201
+ 'nth-child': function(m) {
2202
+ return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
2203
+ },
2204
+ 'nth-last-child': function(m) {
2205
+ return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
2206
+ },
2207
+ 'nth-of-type': function(m) {
2208
+ return Selector.xpath.pseudos.nth("position() ", m);
2209
+ },
2210
+ 'nth-last-of-type': function(m) {
2211
+ return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
2212
+ },
2213
+ 'first-of-type': function(m) {
2214
+ m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
2215
+ },
2216
+ 'last-of-type': function(m) {
2217
+ m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
2218
+ },
2219
+ 'only-of-type': function(m) {
2220
+ var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
2221
+ },
2222
+ nth: function(fragment, m) {
2223
+ var mm, formula = m[6], predicate;
2224
+ if (formula == 'even') formula = '2n+0';
2225
+ if (formula == 'odd') formula = '2n+1';
2226
+ if (mm = formula.match(/^(\d+)$/)) // digit only
2227
+ return '[' + fragment + "= " + mm[1] + ']';
2228
+ if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2229
+ if (mm[1] == "-") mm[1] = -1;
2230
+ var a = mm[1] ? Number(mm[1]) : 1;
2231
+ var b = mm[2] ? Number(mm[2]) : 0;
2232
+ predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
2233
+ "((#{fragment} - #{b}) div #{a} >= 0)]";
2234
+ return new Template(predicate).evaluate({
2235
+ fragment: fragment, a: a, b: b });
2236
+ }
2237
+ }
2238
+ }
2239
+ },
2240
+
2241
+ criteria: {
2242
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2243
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
2244
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
2245
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
2246
+ attr: function(m) {
2247
+ m[3] = (m[5] || m[6]);
2248
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
2249
+ },
2250
+ pseudo: function(m) {
2251
+ if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
2252
+ return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
2253
+ },
2254
+ descendant: 'c = "descendant";',
2255
+ child: 'c = "child";',
2256
+ adjacent: 'c = "adjacent";',
2257
+ laterSibling: 'c = "laterSibling";'
2258
+ },
2259
+
2260
+ patterns: {
2261
+ // combinators must be listed first
2262
+ // (and descendant needs to be last combinator)
2263
+ laterSibling: /^\s*~\s*/,
2264
+ child: /^\s*>\s*/,
2265
+ adjacent: /^\s*\+\s*/,
2266
+ descendant: /^\s/,
2267
+
2268
+ // selectors follow
2269
+ tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
2270
+ id: /^#([\w\-\*]+)(\b|$)/,
2271
+ className: /^\.([\w\-\*]+)(\b|$)/,
2272
+ pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
2273
+ attrPresence: /^\[([\w]+)\]/,
2274
+ attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
2275
+ },
2276
+
2277
+ handlers: {
2278
+ // UTILITY FUNCTIONS
2279
+ // joins two collections
2280
+ concat: function(a, b) {
2281
+ for (var i = 0, node; node = b[i]; i++)
2282
+ a.push(node);
2283
+ return a;
2284
+ },
2285
+
2286
+ // marks an array of nodes for counting
2287
+ mark: function(nodes) {
2288
+ for (var i = 0, node; node = nodes[i]; i++)
2289
+ node._counted = true;
2290
+ return nodes;
2291
+ },
2292
+
2293
+ unmark: function(nodes) {
2294
+ for (var i = 0, node; node = nodes[i]; i++)
2295
+ node._counted = undefined;
2296
+ return nodes;
2297
+ },
2298
+
2299
+ // mark each child node with its position (for nth calls)
2300
+ // "ofType" flag indicates whether we're indexing for nth-of-type
2301
+ // rather than nth-child
2302
+ index: function(parentNode, reverse, ofType) {
2303
+ parentNode._counted = true;
2304
+ if (reverse) {
2305
+ for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
2306
+ node = nodes[i];
2307
+ if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
2308
+ }
2309
+ } else {
2310
+ for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
2311
+ if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
2312
+ }
2313
+ },
2314
+
2315
+ // filters out duplicates and extends all nodes
2316
+ unique: function(nodes) {
2317
+ if (nodes.length == 0) return nodes;
2318
+ var results = [], n;
2319
+ for (var i = 0, l = nodes.length; i < l; i++)
2320
+ if (!(n = nodes[i])._counted) {
2321
+ n._counted = true;
2322
+ results.push(Element.extend(n));
2323
+ }
2324
+ return Selector.handlers.unmark(results);
2325
+ },
2326
+
2327
+ // COMBINATOR FUNCTIONS
2328
+ descendant: function(nodes) {
2329
+ var h = Selector.handlers;
2330
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2331
+ h.concat(results, node.getElementsByTagName('*'));
2332
+ return results;
2333
+ },
2334
+
2335
+ child: function(nodes) {
2336
+ var h = Selector.handlers;
2337
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2338
+ for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
2339
+ if (child.nodeType == 1 && child.tagName != '!') results.push(child);
2340
+ }
2341
+ return results;
2342
+ },
2343
+
2344
+ adjacent: function(nodes) {
2345
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2346
+ var next = this.nextElementSibling(node);
2347
+ if (next) results.push(next);
2348
+ }
2349
+ return results;
2350
+ },
2351
+
2352
+ laterSibling: function(nodes) {
2353
+ var h = Selector.handlers;
2354
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2355
+ h.concat(results, Element.nextSiblings(node));
2356
+ return results;
2357
+ },
2358
+
2359
+ nextElementSibling: function(node) {
2360
+ while (node = node.nextSibling)
2361
+ if (node.nodeType == 1) return node;
2362
+ return null;
2363
+ },
2364
+
2365
+ previousElementSibling: function(node) {
2366
+ while (node = node.previousSibling)
2367
+ if (node.nodeType == 1) return node;
2368
+ return null;
2369
+ },
2370
+
2371
+ // TOKEN FUNCTIONS
2372
+ tagName: function(nodes, root, tagName, combinator) {
2373
+ tagName = tagName.toUpperCase();
2374
+ var results = [], h = Selector.handlers;
2375
+ if (nodes) {
2376
+ if (combinator) {
2377
+ // fastlane for ordinary descendant combinators
2378
+ if (combinator == "descendant") {
2379
+ for (var i = 0, node; node = nodes[i]; i++)
2380
+ h.concat(results, node.getElementsByTagName(tagName));
2381
+ return results;
2382
+ } else nodes = this[combinator](nodes);
2383
+ if (tagName == "*") return nodes;
2384
+ }
2385
+ for (var i = 0, node; node = nodes[i]; i++)
2386
+ if (node.tagName.toUpperCase() == tagName) results.push(node);
2387
+ return results;
2388
+ } else return root.getElementsByTagName(tagName);
2389
+ },
2390
+
2391
+ id: function(nodes, root, id, combinator) {
2392
+ var targetNode = $(id), h = Selector.handlers;
2393
+ if (!nodes && root == document) return targetNode ? [targetNode] : [];
2394
+ if (nodes) {
2395
+ if (combinator) {
2396
+ if (combinator == 'child') {
2397
+ for (var i = 0, node; node = nodes[i]; i++)
2398
+ if (targetNode.parentNode == node) return [targetNode];
2399
+ } else if (combinator == 'descendant') {
2400
+ for (var i = 0, node; node = nodes[i]; i++)
2401
+ if (Element.descendantOf(targetNode, node)) return [targetNode];
2402
+ } else if (combinator == 'adjacent') {
2403
+ for (var i = 0, node; node = nodes[i]; i++)
2404
+ if (Selector.handlers.previousElementSibling(targetNode) == node)
2405
+ return [targetNode];
2406
+ } else nodes = h[combinator](nodes);
2407
+ }
2408
+ for (var i = 0, node; node = nodes[i]; i++)
2409
+ if (node == targetNode) return [targetNode];
2410
+ return [];
2411
+ }
2412
+ return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
2413
+ },
2414
+
2415
+ className: function(nodes, root, className, combinator) {
2416
+ if (nodes && combinator) nodes = this[combinator](nodes);
2417
+ return Selector.handlers.byClassName(nodes, root, className);
2418
+ },
2419
+
2420
+ byClassName: function(nodes, root, className) {
2421
+ if (!nodes) nodes = Selector.handlers.descendant([root]);
2422
+ var needle = ' ' + className + ' ';
2423
+ for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
2424
+ nodeClassName = node.className;
2425
+ if (nodeClassName.length == 0) continue;
2426
+ if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
2427
+ results.push(node);
2428
+ }
2429
+ return results;
2430
+ },
2431
+
2432
+ attrPresence: function(nodes, root, attr) {
2433
+ var results = [];
2434
+ for (var i = 0, node; node = nodes[i]; i++)
2435
+ if (Element.hasAttribute(node, attr)) results.push(node);
2436
+ return results;
2437
+ },
2438
+
2439
+ attr: function(nodes, root, attr, value, operator) {
2440
+ if (!nodes) nodes = root.getElementsByTagName("*");
2441
+ var handler = Selector.operators[operator], results = [];
2442
+ for (var i = 0, node; node = nodes[i]; i++) {
2443
+ var nodeValue = Element.readAttribute(node, attr);
2444
+ if (nodeValue === null) continue;
2445
+ if (handler(nodeValue, value)) results.push(node);
2446
+ }
2447
+ return results;
2448
+ },
2449
+
2450
+ pseudo: function(nodes, name, value, root, combinator) {
2451
+ if (nodes && combinator) nodes = this[combinator](nodes);
2452
+ if (!nodes) nodes = root.getElementsByTagName("*");
2453
+ return Selector.pseudos[name](nodes, value, root);
2454
+ }
2455
+ },
2456
+
2457
+ pseudos: {
2458
+ 'first-child': function(nodes, value, root) {
2459
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2460
+ if (Selector.handlers.previousElementSibling(node)) continue;
2461
+ results.push(node);
2462
+ }
2463
+ return results;
2464
+ },
2465
+ 'last-child': function(nodes, value, root) {
2466
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2467
+ if (Selector.handlers.nextElementSibling(node)) continue;
2468
+ results.push(node);
2469
+ }
2470
+ return results;
2471
+ },
2472
+ 'only-child': function(nodes, value, root) {
2473
+ var h = Selector.handlers;
2474
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2475
+ if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
2476
+ results.push(node);
2477
+ return results;
2478
+ },
2479
+ 'nth-child': function(nodes, formula, root) {
2480
+ return Selector.pseudos.nth(nodes, formula, root);
2481
+ },
2482
+ 'nth-last-child': function(nodes, formula, root) {
2483
+ return Selector.pseudos.nth(nodes, formula, root, true);
2484
+ },
2485
+ 'nth-of-type': function(nodes, formula, root) {
2486
+ return Selector.pseudos.nth(nodes, formula, root, false, true);
2487
+ },
2488
+ 'nth-last-of-type': function(nodes, formula, root) {
2489
+ return Selector.pseudos.nth(nodes, formula, root, true, true);
2490
+ },
2491
+ 'first-of-type': function(nodes, formula, root) {
2492
+ return Selector.pseudos.nth(nodes, "1", root, false, true);
2493
+ },
2494
+ 'last-of-type': function(nodes, formula, root) {
2495
+ return Selector.pseudos.nth(nodes, "1", root, true, true);
2496
+ },
2497
+ 'only-of-type': function(nodes, formula, root) {
2498
+ var p = Selector.pseudos;
2499
+ return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
2500
+ },
2501
+
2502
+ // handles the an+b logic
2503
+ getIndices: function(a, b, total) {
2504
+ if (a == 0) return b > 0 ? [b] : [];
2505
+ return $R(1, total).inject([], function(memo, i) {
2506
+ if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
2507
+ return memo;
2508
+ });
2509
+ },
2510
+
2511
+ // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
2512
+ nth: function(nodes, formula, root, reverse, ofType) {
2513
+ if (nodes.length == 0) return [];
2514
+ if (formula == 'even') formula = '2n+0';
2515
+ if (formula == 'odd') formula = '2n+1';
2516
+ var h = Selector.handlers, results = [], indexed = [], m;
2517
+ h.mark(nodes);
2518
+ for (var i = 0, node; node = nodes[i]; i++) {
2519
+ if (!node.parentNode._counted) {
2520
+ h.index(node.parentNode, reverse, ofType);
2521
+ indexed.push(node.parentNode);
2522
+ }
2523
+ }
2524
+ if (formula.match(/^\d+$/)) { // just a number
2525
+ formula = Number(formula);
2526
+ for (var i = 0, node; node = nodes[i]; i++)
2527
+ if (node.nodeIndex == formula) results.push(node);
2528
+ } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2529
+ if (m[1] == "-") m[1] = -1;
2530
+ var a = m[1] ? Number(m[1]) : 1;
2531
+ var b = m[2] ? Number(m[2]) : 0;
2532
+ var indices = Selector.pseudos.getIndices(a, b, nodes.length);
2533
+ for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
2534
+ for (var j = 0; j < l; j++)
2535
+ if (node.nodeIndex == indices[j]) results.push(node);
2536
+ }
2537
+ }
2538
+ h.unmark(nodes);
2539
+ h.unmark(indexed);
2540
+ return results;
2541
+ },
2542
+
2543
+ 'empty': function(nodes, value, root) {
2544
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2545
+ // IE treats comments as element nodes
2546
+ if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
2547
+ results.push(node);
2548
+ }
2549
+ return results;
2550
+ },
2551
+
2552
+ 'not': function(nodes, selector, root) {
2553
+ var h = Selector.handlers, selectorType, m;
2554
+ var exclusions = new Selector(selector).findElements(root);
2555
+ h.mark(exclusions);
2556
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2557
+ if (!node._counted) results.push(node);
2558
+ h.unmark(exclusions);
2559
+ return results;
2560
+ },
2561
+
2562
+ 'enabled': function(nodes, value, root) {
2563
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2564
+ if (!node.disabled) results.push(node);
2565
+ return results;
2566
+ },
2567
+
2568
+ 'disabled': function(nodes, value, root) {
2569
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2570
+ if (node.disabled) results.push(node);
2571
+ return results;
2572
+ },
2573
+
2574
+ 'checked': function(nodes, value, root) {
2575
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2576
+ if (node.checked) results.push(node);
2577
+ return results;
2578
+ }
2579
+ },
2580
+
2581
+ operators: {
2582
+ '=': function(nv, v) { return nv == v; },
2583
+ '!=': function(nv, v) { return nv != v; },
2584
+ '^=': function(nv, v) { return nv.startsWith(v); },
2585
+ '$=': function(nv, v) { return nv.endsWith(v); },
2586
+ '*=': function(nv, v) { return nv.include(v); },
2587
+ '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
2588
+ '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
2589
+ },
2590
+
2591
+ matchElements: function(elements, expression) {
2592
+ var matches = new Selector(expression).findElements(), h = Selector.handlers;
2593
+ h.mark(matches);
2594
+ for (var i = 0, results = [], element; element = elements[i]; i++)
2595
+ if (element._counted) results.push(element);
2596
+ h.unmark(matches);
2597
+ return results;
2598
+ },
2599
+
2600
+ findElement: function(elements, expression, index) {
2601
+ if (typeof expression == 'number') {
2602
+ index = expression; expression = false;
2603
+ }
2604
+ return Selector.matchElements(elements, expression || '*')[index || 0];
2605
+ },
2606
+
2607
+ findChildElements: function(element, expressions) {
2608
+ var exprs = expressions.join(','), expressions = [];
2609
+ exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
2610
+ expressions.push(m[1].strip());
2611
+ });
2612
+ var results = [], h = Selector.handlers;
2613
+ for (var i = 0, l = expressions.length, selector; i < l; i++) {
2614
+ selector = new Selector(expressions[i].strip());
2615
+ h.concat(results, selector.findElements(element));
2616
+ }
2617
+ return (l > 1) ? h.unique(results) : results;
2618
+ }
2619
+ });
2620
+
2621
+ function $$() {
2622
+ return Selector.findChildElements(document, $A(arguments));
2623
+ }
2624
+ var Form = {
2625
+ reset: function(form) {
2626
+ $(form).reset();
2627
+ return form;
2628
+ },
2629
+
2630
+ serializeElements: function(elements, getHash) {
2631
+ var data = elements.inject({}, function(result, element) {
2632
+ if (!element.disabled && element.name) {
2633
+ var key = element.name, value = $(element).getValue();
2634
+ if (value != null) {
2635
+ if (key in result) {
2636
+ if (result[key].constructor != Array) result[key] = [result[key]];
2637
+ result[key].push(value);
2638
+ }
2639
+ else result[key] = value;
2640
+ }
2641
+ }
2642
+ return result;
2643
+ });
2644
+
2645
+ return getHash ? data : Hash.toQueryString(data);
2646
+ }
2647
+ };
2648
+
2649
+ Form.Methods = {
2650
+ serialize: function(form, getHash) {
2651
+ return Form.serializeElements(Form.getElements(form), getHash);
2652
+ },
2653
+
2654
+ getElements: function(form) {
2655
+ return $A($(form).getElementsByTagName('*')).inject([],
2656
+ function(elements, child) {
2657
+ if (Form.Element.Serializers[child.tagName.toLowerCase()])
2658
+ elements.push(Element.extend(child));
2659
+ return elements;
2660
+ }
2661
+ );
2662
+ },
2663
+
2664
+ getInputs: function(form, typeName, name) {
2665
+ form = $(form);
2666
+ var inputs = form.getElementsByTagName('input');
2667
+
2668
+ if (!typeName && !name) return $A(inputs).map(Element.extend);
2669
+
2670
+ for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
2671
+ var input = inputs[i];
2672
+ if ((typeName && input.type != typeName) || (name && input.name != name))
2673
+ continue;
2674
+ matchingInputs.push(Element.extend(input));
2675
+ }
2676
+
2677
+ return matchingInputs;
2678
+ },
2679
+
2680
+ disable: function(form) {
2681
+ form = $(form);
2682
+ Form.getElements(form).invoke('disable');
2683
+ return form;
2684
+ },
2685
+
2686
+ enable: function(form) {
2687
+ form = $(form);
2688
+ Form.getElements(form).invoke('enable');
2689
+ return form;
2690
+ },
2691
+
2692
+ findFirstElement: function(form) {
2693
+ return $(form).getElements().find(function(element) {
2694
+ return element.type != 'hidden' && !element.disabled &&
2695
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
2696
+ });
2697
+ },
2698
+
2699
+ focusFirstElement: function(form) {
2700
+ form = $(form);
2701
+ form.findFirstElement().activate();
2702
+ return form;
2703
+ },
2704
+
2705
+ request: function(form, options) {
2706
+ form = $(form), options = Object.clone(options || {});
2707
+
2708
+ var params = options.parameters;
2709
+ options.parameters = form.serialize(true);
2710
+
2711
+ if (params) {
2712
+ if (typeof params == 'string') params = params.toQueryParams();
2713
+ Object.extend(options.parameters, params);
2714
+ }
2715
+
2716
+ if (form.hasAttribute('method') && !options.method)
2717
+ options.method = form.method;
2718
+
2719
+ return new Ajax.Request(form.readAttribute('action'), options);
2720
+ }
2721
+ }
2722
+
2723
+ /*--------------------------------------------------------------------------*/
2724
+
2725
+ Form.Element = {
2726
+ focus: function(element) {
2727
+ $(element).focus();
2728
+ return element;
2729
+ },
2730
+
2731
+ select: function(element) {
2732
+ $(element).select();
2733
+ return element;
2734
+ }
2735
+ }
2736
+
2737
+ Form.Element.Methods = {
2738
+ serialize: function(element) {
2739
+ element = $(element);
2740
+ if (!element.disabled && element.name) {
2741
+ var value = element.getValue();
2742
+ if (value != undefined) {
2743
+ var pair = {};
2744
+ pair[element.name] = value;
2745
+ return Hash.toQueryString(pair);
2746
+ }
2747
+ }
2748
+ return '';
2749
+ },
2750
+
2751
+ getValue: function(element) {
2752
+ element = $(element);
2753
+ var method = element.tagName.toLowerCase();
2754
+ return Form.Element.Serializers[method](element);
2755
+ },
2756
+
2757
+ clear: function(element) {
2758
+ $(element).value = '';
2759
+ return element;
2760
+ },
2761
+
2762
+ present: function(element) {
2763
+ return $(element).value != '';
2764
+ },
2765
+
2766
+ activate: function(element) {
2767
+ element = $(element);
2768
+ try {
2769
+ element.focus();
2770
+ if (element.select && (element.tagName.toLowerCase() != 'input' ||
2771
+ !['button', 'reset', 'submit'].include(element.type)))
2772
+ element.select();
2773
+ } catch (e) {}
2774
+ return element;
2775
+ },
2776
+
2777
+ disable: function(element) {
2778
+ element = $(element);
2779
+ element.blur();
2780
+ element.disabled = true;
2781
+ return element;
2782
+ },
2783
+
2784
+ enable: function(element) {
2785
+ element = $(element);
2786
+ element.disabled = false;
2787
+ return element;
2788
+ }
2789
+ }
2790
+
2791
+ /*--------------------------------------------------------------------------*/
2792
+
2793
+ var Field = Form.Element;
2794
+ var $F = Form.Element.Methods.getValue;
2795
+
2796
+ /*--------------------------------------------------------------------------*/
2797
+
2798
+ Form.Element.Serializers = {
2799
+ input: function(element) {
2800
+ switch (element.type.toLowerCase()) {
2801
+ case 'checkbox':
2802
+ case 'radio':
2803
+ return Form.Element.Serializers.inputSelector(element);
2804
+ default:
2805
+ return Form.Element.Serializers.textarea(element);
2806
+ }
2807
+ },
2808
+
2809
+ inputSelector: function(element) {
2810
+ return element.checked ? element.value : null;
2811
+ },
2812
+
2813
+ textarea: function(element) {
2814
+ return element.value;
2815
+ },
2816
+
2817
+ select: function(element) {
2818
+ return this[element.type == 'select-one' ?
2819
+ 'selectOne' : 'selectMany'](element);
2820
+ },
2821
+
2822
+ selectOne: function(element) {
2823
+ var index = element.selectedIndex;
2824
+ return index >= 0 ? this.optionValue(element.options[index]) : null;
2825
+ },
2826
+
2827
+ selectMany: function(element) {
2828
+ var values, length = element.length;
2829
+ if (!length) return null;
2830
+
2831
+ for (var i = 0, values = []; i < length; i++) {
2832
+ var opt = element.options[i];
2833
+ if (opt.selected) values.push(this.optionValue(opt));
2834
+ }
2835
+ return values;
2836
+ },
2837
+
2838
+ optionValue: function(opt) {
2839
+ // extend element because hasAttribute may not be native
2840
+ return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
2841
+ }
2842
+ }
2843
+
2844
+ /*--------------------------------------------------------------------------*/
2845
+
2846
+ Abstract.TimedObserver = function() {}
2847
+ Abstract.TimedObserver.prototype = {
2848
+ initialize: function(element, frequency, callback) {
2849
+ this.frequency = frequency;
2850
+ this.element = $(element);
2851
+ this.callback = callback;
2852
+
2853
+ this.lastValue = this.getValue();
2854
+ this.registerCallback();
2855
+ },
2856
+
2857
+ registerCallback: function() {
2858
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
2859
+ },
2860
+
2861
+ onTimerEvent: function() {
2862
+ var value = this.getValue();
2863
+ var changed = ('string' == typeof this.lastValue && 'string' == typeof value
2864
+ ? this.lastValue != value : String(this.lastValue) != String(value));
2865
+ if (changed) {
2866
+ this.callback(this.element, value);
2867
+ this.lastValue = value;
2868
+ }
2869
+ }
2870
+ }
2871
+
2872
+ Form.Element.Observer = Class.create();
2873
+ Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2874
+ getValue: function() {
2875
+ return Form.Element.getValue(this.element);
2876
+ }
2877
+ });
2878
+
2879
+ Form.Observer = Class.create();
2880
+ Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2881
+ getValue: function() {
2882
+ return Form.serialize(this.element);
2883
+ }
2884
+ });
2885
+
2886
+ /*--------------------------------------------------------------------------*/
2887
+
2888
+ Abstract.EventObserver = function() {}
2889
+ Abstract.EventObserver.prototype = {
2890
+ initialize: function(element, callback) {
2891
+ this.element = $(element);
2892
+ this.callback = callback;
2893
+
2894
+ this.lastValue = this.getValue();
2895
+ if (this.element.tagName.toLowerCase() == 'form')
2896
+ this.registerFormCallbacks();
2897
+ else
2898
+ this.registerCallback(this.element);
2899
+ },
2900
+
2901
+ onElementEvent: function() {
2902
+ var value = this.getValue();
2903
+ if (this.lastValue != value) {
2904
+ this.callback(this.element, value);
2905
+ this.lastValue = value;
2906
+ }
2907
+ },
2908
+
2909
+ registerFormCallbacks: function() {
2910
+ Form.getElements(this.element).each(this.registerCallback.bind(this));
2911
+ },
2912
+
2913
+ registerCallback: function(element) {
2914
+ if (element.type) {
2915
+ switch (element.type.toLowerCase()) {
2916
+ case 'checkbox':
2917
+ case 'radio':
2918
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
2919
+ break;
2920
+ default:
2921
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
2922
+ break;
2923
+ }
2924
+ }
2925
+ }
2926
+ }
2927
+
2928
+ Form.Element.EventObserver = Class.create();
2929
+ Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2930
+ getValue: function() {
2931
+ return Form.Element.getValue(this.element);
2932
+ }
2933
+ });
2934
+
2935
+ Form.EventObserver = Class.create();
2936
+ Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2937
+ getValue: function() {
2938
+ return Form.serialize(this.element);
2939
+ }
2940
+ });
2941
+ if (!window.Event) {
2942
+ var Event = new Object();
2943
+ }
2944
+
2945
+ Object.extend(Event, {
2946
+ KEY_BACKSPACE: 8,
2947
+ KEY_TAB: 9,
2948
+ KEY_RETURN: 13,
2949
+ KEY_ESC: 27,
2950
+ KEY_LEFT: 37,
2951
+ KEY_UP: 38,
2952
+ KEY_RIGHT: 39,
2953
+ KEY_DOWN: 40,
2954
+ KEY_DELETE: 46,
2955
+ KEY_HOME: 36,
2956
+ KEY_END: 35,
2957
+ KEY_PAGEUP: 33,
2958
+ KEY_PAGEDOWN: 34,
2959
+
2960
+ element: function(event) {
2961
+ return $(event.target || event.srcElement);
2962
+ },
2963
+
2964
+ isLeftClick: function(event) {
2965
+ return (((event.which) && (event.which == 1)) ||
2966
+ ((event.button) && (event.button == 1)));
2967
+ },
2968
+
2969
+ pointerX: function(event) {
2970
+ return event.pageX || (event.clientX +
2971
+ (document.documentElement.scrollLeft || document.body.scrollLeft));
2972
+ },
2973
+
2974
+ pointerY: function(event) {
2975
+ return event.pageY || (event.clientY +
2976
+ (document.documentElement.scrollTop || document.body.scrollTop));
2977
+ },
2978
+
2979
+ stop: function(event) {
2980
+ if (event.preventDefault) {
2981
+ event.preventDefault();
2982
+ event.stopPropagation();
2983
+ } else {
2984
+ event.returnValue = false;
2985
+ event.cancelBubble = true;
2986
+ }
2987
+ },
2988
+
2989
+ // find the first node with the given tagName, starting from the
2990
+ // node the event was triggered on; traverses the DOM upwards
2991
+ findElement: function(event, tagName) {
2992
+ var element = Event.element(event);
2993
+ while (element.parentNode && (!element.tagName ||
2994
+ (element.tagName.toUpperCase() != tagName.toUpperCase())))
2995
+ element = element.parentNode;
2996
+ return element;
2997
+ },
2998
+
2999
+ observers: false,
3000
+
3001
+ _observeAndCache: function(element, name, observer, useCapture) {
3002
+ if (!this.observers) this.observers = [];
3003
+ if (element.addEventListener) {
3004
+ this.observers.push([element, name, observer, useCapture]);
3005
+ element.addEventListener(name, observer, useCapture);
3006
+ } else if (element.attachEvent) {
3007
+ this.observers.push([element, name, observer, useCapture]);
3008
+ element.attachEvent('on' + name, observer);
3009
+ }
3010
+ },
3011
+
3012
+ unloadCache: function() {
3013
+ if (!Event.observers) return;
3014
+ for (var i = 0, length = Event.observers.length; i < length; i++) {
3015
+ Event.stopObserving.apply(this, Event.observers[i]);
3016
+ Event.observers[i][0] = null;
3017
+ }
3018
+ Event.observers = false;
3019
+ },
3020
+
3021
+ observe: function(element, name, observer, useCapture) {
3022
+ element = $(element);
3023
+ useCapture = useCapture || false;
3024
+
3025
+ if (name == 'keypress' &&
3026
+ (Prototype.Browser.WebKit || element.attachEvent))
3027
+ name = 'keydown';
3028
+
3029
+ Event._observeAndCache(element, name, observer, useCapture);
3030
+ },
3031
+
3032
+ stopObserving: function(element, name, observer, useCapture) {
3033
+ element = $(element);
3034
+ useCapture = useCapture || false;
3035
+
3036
+ if (name == 'keypress' &&
3037
+ (Prototype.Browser.WebKit || element.attachEvent))
3038
+ name = 'keydown';
3039
+
3040
+ if (element.removeEventListener) {
3041
+ element.removeEventListener(name, observer, useCapture);
3042
+ } else if (element.detachEvent) {
3043
+ try {
3044
+ element.detachEvent('on' + name, observer);
3045
+ } catch (e) {}
3046
+ }
3047
+ }
3048
+ });
3049
+
3050
+ /* prevent memory leaks in IE */
3051
+ if (Prototype.Browser.IE)
3052
+ Event.observe(window, 'unload', Event.unloadCache, false);
3053
+ var Position = {
3054
+ // set to true if needed, warning: firefox performance problems
3055
+ // NOT neeeded for page scrolling, only if draggable contained in
3056
+ // scrollable elements
3057
+ includeScrollOffsets: false,
3058
+
3059
+ // must be called before calling withinIncludingScrolloffset, every time the
3060
+ // page is scrolled
3061
+ prepare: function() {
3062
+ this.deltaX = window.pageXOffset
3063
+ || document.documentElement.scrollLeft
3064
+ || document.body.scrollLeft
3065
+ || 0;
3066
+ this.deltaY = window.pageYOffset
3067
+ || document.documentElement.scrollTop
3068
+ || document.body.scrollTop
3069
+ || 0;
3070
+ },
3071
+
3072
+ realOffset: function(element) {
3073
+ var valueT = 0, valueL = 0;
3074
+ do {
3075
+ valueT += element.scrollTop || 0;
3076
+ valueL += element.scrollLeft || 0;
3077
+ element = element.parentNode;
3078
+ } while (element);
3079
+ return [valueL, valueT];
3080
+ },
3081
+
3082
+ cumulativeOffset: function(element) {
3083
+ var valueT = 0, valueL = 0;
3084
+ do {
3085
+ valueT += element.offsetTop || 0;
3086
+ valueL += element.offsetLeft || 0;
3087
+ element = element.offsetParent;
3088
+ } while (element);
3089
+ return [valueL, valueT];
3090
+ },
3091
+
3092
+ positionedOffset: function(element) {
3093
+ var valueT = 0, valueL = 0;
3094
+ do {
3095
+ valueT += element.offsetTop || 0;
3096
+ valueL += element.offsetLeft || 0;
3097
+ element = element.offsetParent;
3098
+ if (element) {
3099
+ if(element.tagName=='BODY') break;
3100
+ var p = Element.getStyle(element, 'position');
3101
+ if (p == 'relative' || p == 'absolute') break;
3102
+ }
3103
+ } while (element);
3104
+ return [valueL, valueT];
3105
+ },
3106
+
3107
+ offsetParent: function(element) {
3108
+ if (element.offsetParent) return element.offsetParent;
3109
+ if (element == document.body) return element;
3110
+
3111
+ while ((element = element.parentNode) && element != document.body)
3112
+ if (Element.getStyle(element, 'position') != 'static')
3113
+ return element;
3114
+
3115
+ return document.body;
3116
+ },
3117
+
3118
+ // caches x/y coordinate pair to use with overlap
3119
+ within: function(element, x, y) {
3120
+ if (this.includeScrollOffsets)
3121
+ return this.withinIncludingScrolloffsets(element, x, y);
3122
+ this.xcomp = x;
3123
+ this.ycomp = y;
3124
+ this.offset = this.cumulativeOffset(element);
3125
+
3126
+ return (y >= this.offset[1] &&
3127
+ y < this.offset[1] + element.offsetHeight &&
3128
+ x >= this.offset[0] &&
3129
+ x < this.offset[0] + element.offsetWidth);
3130
+ },
3131
+
3132
+ withinIncludingScrolloffsets: function(element, x, y) {
3133
+ var offsetcache = this.realOffset(element);
3134
+
3135
+ this.xcomp = x + offsetcache[0] - this.deltaX;
3136
+ this.ycomp = y + offsetcache[1] - this.deltaY;
3137
+ this.offset = this.cumulativeOffset(element);
3138
+
3139
+ return (this.ycomp >= this.offset[1] &&
3140
+ this.ycomp < this.offset[1] + element.offsetHeight &&
3141
+ this.xcomp >= this.offset[0] &&
3142
+ this.xcomp < this.offset[0] + element.offsetWidth);
3143
+ },
3144
+
3145
+ // within must be called directly before
3146
+ overlap: function(mode, element) {
3147
+ if (!mode) return 0;
3148
+ if (mode == 'vertical')
3149
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
3150
+ element.offsetHeight;
3151
+ if (mode == 'horizontal')
3152
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
3153
+ element.offsetWidth;
3154
+ },
3155
+
3156
+ page: function(forElement) {
3157
+ var valueT = 0, valueL = 0;
3158
+
3159
+ var element = forElement;
3160
+ do {
3161
+ valueT += element.offsetTop || 0;
3162
+ valueL += element.offsetLeft || 0;
3163
+
3164
+ // Safari fix
3165
+ if (element.offsetParent == document.body)
3166
+ if (Element.getStyle(element,'position')=='absolute') break;
3167
+
3168
+ } while (element = element.offsetParent);
3169
+
3170
+ element = forElement;
3171
+ do {
3172
+ if (!window.opera || element.tagName=='BODY') {
3173
+ valueT -= element.scrollTop || 0;
3174
+ valueL -= element.scrollLeft || 0;
3175
+ }
3176
+ } while (element = element.parentNode);
3177
+
3178
+ return [valueL, valueT];
3179
+ },
3180
+
3181
+ clone: function(source, target) {
3182
+ var options = Object.extend({
3183
+ setLeft: true,
3184
+ setTop: true,
3185
+ setWidth: true,
3186
+ setHeight: true,
3187
+ offsetTop: 0,
3188
+ offsetLeft: 0
3189
+ }, arguments[2] || {})
3190
+
3191
+ // find page position of source
3192
+ source = $(source);
3193
+ var p = Position.page(source);
3194
+
3195
+ // find coordinate system to use
3196
+ target = $(target);
3197
+ var delta = [0, 0];
3198
+ var parent = null;
3199
+ // delta [0,0] will do fine with position: fixed elements,
3200
+ // position:absolute needs offsetParent deltas
3201
+ if (Element.getStyle(target,'position') == 'absolute') {
3202
+ parent = Position.offsetParent(target);
3203
+ delta = Position.page(parent);
3204
+ }
3205
+
3206
+ // correct by body offsets (fixes Safari)
3207
+ if (parent == document.body) {
3208
+ delta[0] -= document.body.offsetLeft;
3209
+ delta[1] -= document.body.offsetTop;
3210
+ }
3211
+
3212
+ // set position
3213
+ if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
3214
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
3215
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
3216
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
3217
+ },
3218
+
3219
+ absolutize: function(element) {
3220
+ element = $(element);
3221
+ if (element.style.position == 'absolute') return;
3222
+ Position.prepare();
3223
+
3224
+ var offsets = Position.positionedOffset(element);
3225
+ var top = offsets[1];
3226
+ var left = offsets[0];
3227
+ var width = element.clientWidth;
3228
+ var height = element.clientHeight;
3229
+
3230
+ element._originalLeft = left - parseFloat(element.style.left || 0);
3231
+ element._originalTop = top - parseFloat(element.style.top || 0);
3232
+ element._originalWidth = element.style.width;
3233
+ element._originalHeight = element.style.height;
3234
+
3235
+ element.style.position = 'absolute';
3236
+ element.style.top = top + 'px';
3237
+ element.style.left = left + 'px';
3238
+ element.style.width = width + 'px';
3239
+ element.style.height = height + 'px';
3240
+ },
3241
+
3242
+ relativize: function(element) {
3243
+ element = $(element);
3244
+ if (element.style.position == 'relative') return;
3245
+ Position.prepare();
3246
+
3247
+ element.style.position = 'relative';
3248
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
3249
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
3250
+
3251
+ element.style.top = top + 'px';
3252
+ element.style.left = left + 'px';
3253
+ element.style.height = element._originalHeight;
3254
+ element.style.width = element._originalWidth;
3255
+ }
3256
+ }
3257
+
3258
+ // Safari returns margins on body which is incorrect if the child is absolutely
3259
+ // positioned. For performance reasons, redefine Position.cumulativeOffset for
3260
+ // KHTML/WebKit only.
3261
+ if (Prototype.Browser.WebKit) {
3262
+ Position.cumulativeOffset = function(element) {
3263
+ var valueT = 0, valueL = 0;
3264
+ do {
3265
+ valueT += element.offsetTop || 0;
3266
+ valueL += element.offsetLeft || 0;
3267
+ if (element.offsetParent == document.body)
3268
+ if (Element.getStyle(element, 'position') == 'absolute') break;
3269
+
3270
+ element = element.offsetParent;
3271
+ } while (element);
3272
+
3273
+ return [valueL, valueT];
3274
+ }
3275
+ }
3276
+
3277
+ Element.addMethods();
downloader/lib/Mage/Archive.php ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Archive
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to work with archives
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Archive
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Archive
35
+ {
36
+
37
+ /**
38
+ * Archiver is used for compress.
39
+ */
40
+ const DEFAULT_ARCHIVER = 'gz';
41
+
42
+ /**
43
+ * Default packer for directory.
44
+ */
45
+ const TAPE_ARCHIVER = 'tar';
46
+
47
+ /**
48
+ * Current archiver is used for compress.
49
+ *
50
+ * @var Mage_Archiver_Tar|Mage_Archiver_Gz|Mage_Archiver_Bz
51
+ */
52
+ protected $_archiver=null;
53
+
54
+ /**
55
+ * Accessible formats for compress.
56
+ *
57
+ * @var array
58
+ */
59
+ protected $_formats = array(
60
+ 'tar' => 'tar',
61
+ 'gz' => 'gz',
62
+ 'gzip' => 'gz',
63
+ 'tgz' => 'tar.gz',
64
+ 'tgzip' => 'tar.gz',
65
+ 'bz' => 'bz',
66
+ 'bzip' => 'bz',
67
+ 'bzip2' => 'bz',
68
+ 'bz2' => 'bz',
69
+ 'tbz' => 'tar.bz',
70
+ 'tbzip' => 'tar.bz',
71
+ 'tbz2' => 'tar.bz',
72
+ 'tbzip2' => 'tar.bz');
73
+
74
+ /**
75
+ * Create object of current archiver by $extension.
76
+ *
77
+ * @param string $extension
78
+ * @return Mage_Archiver_Tar|Mage_Archiver_Gz|Mage_Archiver_Bz
79
+ */
80
+ protected function _getArchiver($extension)
81
+ {
82
+ if(array_key_exists(strtolower($extension), $this->_formats)) {
83
+ $format = $this->_formats[$extension];
84
+ } else {
85
+ $format = self::DEFAULT_ARCHIVER;
86
+ }
87
+ $class = 'Mage_Archive_'.ucfirst($format);
88
+ $this->_archiver = new $class();
89
+ return $this->_archiver;
90
+ }
91
+
92
+ /**
93
+ * Split current format to list of archivers.
94
+ *
95
+ * @param string $source
96
+ * @return array
97
+ */
98
+ protected function _getArchivers($source)
99
+ {
100
+ $ext = pathinfo($source, PATHINFO_EXTENSION);
101
+ if(!isset($this->_formats[$ext])) {
102
+ return array();
103
+ }
104
+ $format = $this->_formats[$ext];
105
+ if ($format) {
106
+ $archivers = explode('.', $format);
107
+ return $archivers;
108
+ }
109
+ return array();
110
+ }
111
+
112
+ /**
113
+ * Pack file or directory to archivers are parsed from extension.
114
+ *
115
+ * @param string $source
116
+ * @param string $destination
117
+ * @param boolean $skipRoot skip first level parent
118
+ * @return string Path to file
119
+ */
120
+ public function pack($source, $destination='packed.tgz', $skipRoot=false)
121
+ {
122
+ $archivers = $this->_getArchivers($destination);
123
+ $interimSource = '';
124
+ for ($i=0; $i<count($archivers); $i++ ) {
125
+ if ($i == (count($archivers) - 1)) {
126
+ $packed = $destination;
127
+ } else {
128
+ $packed = dirname($destination) . DS . '~tmp-'. microtime(true) . $archivers[$i] . '.' . $archivers[$i];
129
+ }
130
+ $source = $this->_getArchiver($archivers[$i])->pack($source, $packed, $skipRoot);
131
+ if ($interimSource && $i < count($archivers)) {
132
+ unlink($interimSource);
133
+ }
134
+ $interimSource = $source;
135
+ }
136
+ return $source;
137
+ }
138
+
139
+ /**
140
+ * Unpack file from archivers are parsed from extension.
141
+ * If $tillTar == true unpack file from archivers till
142
+ * meet TAR archiver.
143
+ *
144
+ * @param string $source
145
+ * @param string $destination
146
+ * @param boolean $tillTar
147
+ * @return string Path to file
148
+ */
149
+ public function unpack($source, $destination='.', $tillTar=false, $clearInterm = true)
150
+ {
151
+ $archivers = $this->_getArchivers($source);
152
+ $interimSource = '';
153
+ for ($i=count($archivers)-1; $i>=0; $i--) {
154
+ if ($tillTar && $archivers[$i] == self::TAPE_ARCHIVER) {
155
+ break;
156
+ }
157
+ if ($i == 0) {
158
+ $packed = rtrim($destination, DS) . DS;
159
+ } else {
160
+ $packed = rtrim($destination, DS) . DS . '~tmp-'. microtime(true) . $archivers[$i-1] . '.' . $archivers[$i-1];
161
+ }
162
+ $source = $this->_getArchiver($archivers[$i])->unpack($source, $packed);
163
+
164
+ //var_dump($packed, $source);
165
+
166
+ if ($clearInterm && $interimSource && $i >= 0) {
167
+ unlink($interimSource);
168
+ }
169
+ $interimSource = $source;
170
+ }
171
+ return $source;
172
+ }
173
+
174
+ /**
175
+ * Extract one file from TAR (Tape Archiver).
176
+ *
177
+ * @param string $file
178
+ * @param string $source
179
+ * @param string $destination
180
+ * @return string Path to file
181
+ */
182
+ public function extract($file, $source, $destination='.')
183
+ {
184
+ $tarFile = $this->unpack($source, $destination, true);
185
+ $resFile = $this->_getArchiver(self::TAPE_ARCHIVER)->extract($file, $tarFile, $destination);
186
+ if (!$this->isTar($source)) {
187
+ unlink($tarFile);
188
+ }
189
+ return $resFile;
190
+ }
191
+
192
+ /**
193
+ * Check file is archive.
194
+ *
195
+ * @param string $file
196
+ * @return boolean
197
+ */
198
+ public function isArchive($file)
199
+ {
200
+ $archivers = $this->_getArchivers($file);
201
+ if (count($archivers)) {
202
+ return true;
203
+ }
204
+ return false;
205
+ }
206
+
207
+ /**
208
+ * Check file is TAR.
209
+ *
210
+ * @param mixed $file
211
+ * @return boolean
212
+ */
213
+ public function isTar($file)
214
+ {
215
+ $archivers = $this->_getArchivers($file);
216
+ if (count($archivers)==1 && $archivers[0] == self::TAPE_ARCHIVER) {
217
+ return true;
218
+ }
219
+ return false;
220
+ }
221
+
222
+ }
downloader/lib/Mage/Archive/Abstract.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Archive
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to work with archives
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Archive
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Archive_Abstract
35
+ {
36
+ /**
37
+ * Write data to file. If file can't be opened,
38
+ *
39
+ * @param string $destination
40
+ * @param string $data
41
+ * @return boolean
42
+ */
43
+ protected function _writeFile($destination, $data)
44
+ {
45
+ if(false === file_put_contents($destination, $data)) {
46
+ throw new Mage_Exception("Can't write to file: " . $destination);
47
+ }
48
+ return true;
49
+ }
50
+
51
+ /**
52
+ * Read data from file. If file can't be opened, throw to exception.
53
+ *
54
+ * @param string $source
55
+ * @return string
56
+ */
57
+ protected function _readFile($source)
58
+ {
59
+ $data = '';
60
+ if (is_file($source) && is_readable($source)) {
61
+ $data = @file_get_contents($source);
62
+ if ($data === false) {
63
+ throw new Mage_Exception("Can't get contents from: " . $source);
64
+ }
65
+ }
66
+ return $data;
67
+ }
68
+
69
+ /**
70
+ * Get file name from source (URI) without last extension.
71
+ *
72
+ * @param string $source
73
+ * @return string
74
+ */
75
+ public function getFilename($source, $withExtension=false)
76
+ {
77
+ $file = str_replace(dirname($source) . DS, '', $source);
78
+ if (!$withExtension) {
79
+ $file = substr($file, 0, strrpos($file, '.'));
80
+ }
81
+ return $file;
82
+ }
83
+
84
+ }
downloader/lib/Mage/Archive/Bz.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Archive
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to work with bzip2 archives
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Archive
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Archive_Bz extends Mage_Archive_Abstract implements Mage_Archive_Interface
35
+ {
36
+
37
+ /**
38
+ * Pack file by BZIP2 compressor.
39
+ *
40
+ * @param string $source
41
+ * @param string $destination
42
+ * @return string
43
+ */
44
+ public function pack($source, $destination)
45
+ {
46
+ $data = $this->_readFile($source);
47
+ $bzData = bzcompress($data, 9);
48
+ $this->_writeFile($destination, $bzData);
49
+ return $destination;
50
+ }
51
+
52
+ /**
53
+ * Unpack file by BZIP2 compressor.
54
+ *
55
+ * @param string $source
56
+ * @param string $destination
57
+ * @return string
58
+ */
59
+ public function unpack($source, $destination)
60
+ {
61
+ $data = '';
62
+ $bzPointer = bzopen($source, 'r' );
63
+ if (empty($bzPointer)) {
64
+ throw new Exception('Can\'t open BZ archive : ' . $source);
65
+ }
66
+ while (!feof($bzPointer)) {
67
+ $data .= bzread($bzPointer, 131072);
68
+ }
69
+ bzclose($bzPointer);
70
+ if (is_dir($destination)) {
71
+ $file = $this->getFilename($source);
72
+ $destination = $destination . $file;
73
+ }
74
+ echo $destination;
75
+ $this->_writeFile($destination, $data);
76
+ return $destination;
77
+ }
78
+
79
+ }
downloader/lib/Mage/Archive/Gz.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Archive
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to work with gz archives
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Archive
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Archive_Gz extends Mage_Archive_Abstract implements Mage_Archive_Interface
35
+ {
36
+ /**
37
+ * Pack file by GZ compressor.
38
+ *
39
+ * @param string $source
40
+ * @param string $destination
41
+ * @return string
42
+ */
43
+ public function pack($source, $destination)
44
+ {
45
+ $data = $this->_readFile($source);
46
+ $gzData = gzencode($data, 9);
47
+ $this->_writeFile($destination, $gzData);
48
+ return $destination;
49
+ }
50
+
51
+ /**
52
+ * Unpack file by GZ compressor.
53
+ *
54
+ * @param string $source
55
+ * @param string $destination
56
+ * @return string
57
+ */
58
+ public function unpack($source, $destination)
59
+ {
60
+ $gzPointer = gzopen($source, 'r' );
61
+ if (empty($gzPointer)) {
62
+ throw new Mage_Exception('Can\'t open GZ archive : ' . $source);
63
+ }
64
+ $data = '';
65
+ while (!gzeof($gzPointer)) {
66
+ $data .= gzread($gzPointer, 131072);
67
+ }
68
+ gzclose($gzPointer);
69
+ if (is_dir($destination)) {
70
+ $file = $this->getFilename($source);
71
+ $destination = $destination . $file;
72
+ }
73
+ $this->_writeFile($destination, $data);
74
+ return $destination;
75
+ }
76
+
77
+ }
downloader/lib/Mage/Archive/Interface.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Archive
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Interface for work with archives
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Archive
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ interface Mage_Archive_Interface
35
+ {
36
+ /**
37
+ * Pack file or directory.
38
+ *
39
+ * @param string $source
40
+ * @param string $destination
41
+ * @return string
42
+ */
43
+ public function pack($source, $destination);
44
+
45
+ /**
46
+ * Unpack file or directory.
47
+ *
48
+ * @param string $source
49
+ * @param string $destination
50
+ * @return string
51
+ */
52
+ public function unpack($source, $destination);
53
+ }
downloader/lib/Mage/Archive/Tar.php ADDED
@@ -0,0 +1,372 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Archive
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to work with tar archives
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Archive
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Archive_Tar extends Mage_Archive_Abstract implements Mage_Archive_Interface
35
+ {
36
+ /**
37
+ * Constant is used for parse tar's header.
38
+ */
39
+ const FORMAT_PARSE_HEADER = 'a100name/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100symlink/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix/a12closer';
40
+
41
+ /**
42
+ * Keep file or directory for packing.
43
+ *
44
+ * @var string
45
+ */
46
+ protected $_currentFile;
47
+
48
+ /**
49
+ * Keep path to file or directory for packing.
50
+ *
51
+ * @var mixed
52
+ */
53
+ protected $_currentPath;
54
+
55
+ /**
56
+ * Skip first level parent directory. Example:
57
+ * use test/fip.php instead test/test/fip.php;
58
+ *
59
+ * @var mixed
60
+ */
61
+ protected $_skipRoot;
62
+
63
+ /**
64
+ * Set option that define ability skip first catalog level.
65
+ *
66
+ * @param mixed $skipRoot
67
+ * @return Mage_Archive_Tar
68
+ */
69
+ protected function _setSkipRoot($skipRoot)
70
+ {
71
+ $this->_skipRoot = $skipRoot;
72
+ return $this;
73
+ }
74
+
75
+ /**
76
+ * Set file which is packing.
77
+ *
78
+ * @param string $file
79
+ * @return Mage_Archive_Tar
80
+ */
81
+ protected function _setCurrentFile($file)
82
+ {
83
+ $this->_currentFile = $file .((is_dir($file) && substr($file, -1)!=DS)?DS:'');
84
+ return $this;
85
+ }
86
+
87
+ /**
88
+ * Retrieve file which is packing.
89
+ *
90
+ * @return string
91
+ */
92
+ protected function _getCurrentFile()
93
+ {
94
+ return $this->_currentFile;
95
+ }
96
+
97
+ /**
98
+ * Set path to file which is packing.
99
+ *
100
+ * @param string $path
101
+ * @return Mage_Archive_Tar
102
+ */
103
+ protected function _setCurrentPath($path)
104
+ {
105
+ if ($this->_skipRoot && is_dir($path)) {
106
+ $this->_currentPath = $path.(substr($path, -1)!=DS?DS:'');
107
+ } else {
108
+ $this->_currentPath = dirname($path) . DS;
109
+ }
110
+ return $this;
111
+ }
112
+
113
+ /**
114
+ * Retrieve path to file which is packing.
115
+ *
116
+ * @return string
117
+ */
118
+ protected function _getCurrentPath()
119
+ {
120
+ return $this->_currentPath;
121
+ }
122
+
123
+ /**
124
+ * Walk through directory and add to tar file or directory.
125
+ * Result is packed string on TAR format.
126
+ *
127
+ * @param boolean $skipRoot
128
+ * @return string
129
+ */
130
+ protected function _packToTar($skipRoot=false)
131
+ {
132
+ $file = $this->_getCurrentFile();
133
+ $header = '';
134
+ $data = '';
135
+ if (!$skipRoot) {
136
+ $header = $this->_composeHeader();
137
+ $data = $this->_readFile($file);
138
+ $data = str_pad($data, floor(((is_dir($file) ? 0 : filesize($file)) + 512 - 1) / 512) * 512, "\0");
139
+ }
140
+ $sub = '';
141
+ if (is_dir($file)) {
142
+ $treeDir = scandir($file);
143
+ if (empty($treeDir)) {
144
+ throw new Mage_Exception('Can\'t scan dir: ' . $file);
145
+ }
146
+ array_shift($treeDir); /* remove './'*/
147
+ array_shift($treeDir); /* remove '../'*/
148
+ foreach ($treeDir as $item) {
149
+ $sub .= $this->_setCurrentFile($file.$item)->_packToTar(false);
150
+ }
151
+ }
152
+ $tarData = $header . $data . $sub;
153
+ $tarData = str_pad($tarData, floor((strlen($tarData) - 1) / 1536) * 1536, "\0");
154
+ return $tarData;
155
+ }
156
+
157
+ /**
158
+ * Compose header for current file in TAR format.
159
+ * If length of file's name greater 100 characters,
160
+ * method breaks header to two pieces. First conatins
161
+ * header and data with long name. Second contain only header.
162
+ *
163
+ * @param boolean $long
164
+ * @return string
165
+ */
166
+ protected function _composeHeader($long = false)
167
+ {
168
+ $file = $this->_getCurrentFile();
169
+ $path = $this->_getCurrentPath();
170
+ $infoFile = stat($file);
171
+ $nameFile = str_replace($path, '', $file);
172
+ $nameFile = str_replace('\\', '/', $nameFile);
173
+ $packedHeader = '';
174
+ $longHeader = '';
175
+ if (!$long && strlen($nameFile)>100) {
176
+ $longHeader = $this->_composeHeader(true);
177
+ $longHeader .= str_pad($nameFile, floor((strlen($nameFile) + 512 - 1) / 512) * 512, "\0");
178
+ }
179
+ $header = array();
180
+ $header['100-name'] = $long?'././@LongLink':substr($nameFile, 0, 100);
181
+ $header['8-mode'] = $long?' ':str_pad(substr(sprintf("%07o", $infoFile['mode']),-4), 6, '0', STR_PAD_LEFT);
182
+ $header['8-uid'] = $long || $infoFile['uid']==0?"\0\0\0\0\0\0\0":sprintf("%07o", $infoFile['uid']);
183
+ $header['8-gid'] = $long || $infoFile['gid']==0?"\0\0\0\0\0\0\0":sprintf("%07o", $infoFile['gid']);
184
+ $header['12-size'] = $long?sprintf("%011o", strlen($nameFile)):sprintf("%011o", is_dir($file) ? 0 : filesize($file));
185
+ $header['12-mtime'] = $long?'00000000000':sprintf("%011o", $infoFile['mtime']);
186
+ $header['8-check'] = sprintf('% 8s', '');
187
+ $header['1-type'] = $long?'L':(is_link($file) ? 2 : is_dir ($file) ? 5 : 0);
188
+ $header['100-symlink'] = is_link($file) == 2 ? readlink($item) : '';
189
+ $header['6-magic'] = 'ustar ';
190
+ $header['2-version'] = ' ';
191
+ $a=function_exists('posix_getpwuid')?posix_getpwuid (fileowner($file)):array('name'=>'');
192
+ $header['32-uname'] = $a['name'];
193
+ $a=function_exists('posix_getgrgid')?posix_getgrgid (filegroup($file)):array('name'=>'');
194
+ $header['32-gname'] = $a['name'];
195
+ $header['8-devmajor'] = '';
196
+ $header['8-devminor'] = '';
197
+ $header['155-prefix'] = '';
198
+ $header['12-closer'] = '';
199
+
200
+ $packedHeader = '';
201
+ foreach ($header as $key=>$element) {
202
+ $length = explode('-', $key);
203
+ $packedHeader .= pack('a' . $length[0], $element);
204
+ }
205
+
206
+ $checksum = 0;
207
+ for ($i = 0; $i < 512; $i++) {
208
+ $checksum += ord(substr($packedHeader, $i, 1));
209
+ }
210
+ $packedHeader = substr_replace($packedHeader, sprintf("%07o", $checksum)."\0", 148, 8);
211
+
212
+ return $longHeader . $packedHeader;
213
+ }
214
+
215
+ /**
216
+ * Read TAR string from file, and unpacked it.
217
+ * Create files and directories information about discribed
218
+ * in the string.
219
+ *
220
+ * @param string $destination path to file is unpacked
221
+ * @return array list of files
222
+ */
223
+ protected function _unpackCurrentTar($destination)
224
+ {
225
+ $file = $this->_getCurrentFile();
226
+ $pointer = fopen($file, 'r');
227
+ if (empty($pointer)) {
228
+ throw new Mage_Exception('Can\'t open file: ' . $file);
229
+ }
230
+ $list = array();
231
+ while (!feof($pointer)) {
232
+ $header = $this->_parseHeader($pointer);
233
+ if ($header) {
234
+ $currentFile = $destination . $header['name'];
235
+ if ($header['type']=='5' && @mkdir($currentFile, 0777, true)) {
236
+ $list[] = $currentFile . DS;
237
+ } elseif (in_array($header['type'], array("0",chr(0), ''))) {
238
+ $dirname = dirname($currentFile);
239
+ if(!file_exists($dirname)) {
240
+ @mkdir($dirname, 0777, true);
241
+ }
242
+ $this->_writeFile($currentFile, $header['data']);
243
+ $list[] = $currentFile;
244
+ }
245
+ }
246
+ }
247
+ fclose($pointer);
248
+ return $list;
249
+ }
250
+
251
+ /**
252
+ * Get header from TAR string and unpacked it by format.
253
+ *
254
+ * @param resource $pointer
255
+ * @return string
256
+ */
257
+ protected function _parseHeader(&$pointer)
258
+ {
259
+ $firstLine = fread($pointer, 512);
260
+
261
+ if (strlen($firstLine)<512){
262
+ return false;
263
+ }
264
+
265
+ $fmt = self::FORMAT_PARSE_HEADER;
266
+ $header = unpack ($fmt, $firstLine);
267
+
268
+
269
+ $header['mode']=$header['mode']+0;
270
+ $header['uid']=octdec($header['uid']);
271
+ $header['gid']=octdec($header['gid']);
272
+ $header['size']=octdec($header['size']);
273
+ $header['mtime']=octdec($header['mtime']);
274
+ $header['checksum']=octdec($header['checksum']);
275
+
276
+ if ($header['type'] == "5") {
277
+ $header['size'] = 0;
278
+ }
279
+
280
+ $checksum = 0;
281
+ $firstLine = substr_replace($firstLine, ' ', 148, 8);
282
+ for ($i = 0; $i < 512; $i++) {
283
+ $checksum += ord(substr($firstLine, $i, 1));
284
+ }
285
+
286
+ $isUstar = 'ustar' == strtolower(substr($header['magic'], 0, 5));
287
+
288
+ $checksumOk = $header['checksum'] == $checksum;
289
+ if (isset($header['name']) && $checksumOk) {
290
+ if ($header['name'] == '././@LongLink' && $header['type'] == 'L') {
291
+ $realName = substr(fread($pointer, floor(($header['size'] + 512 - 1) / 512) * 512), 0, $header['size']);
292
+ $headerMain = $this->_parseHeader($pointer);
293
+ $headerMain['name'] = $realName;
294
+ return $headerMain;
295
+ } else {
296
+ if ($header['size']>0) {
297
+ $header['data'] = substr(fread($pointer, floor(($header['size'] + 512 - 1) / 512) * 512), 0, $header['size']);
298
+ } else {
299
+ $header['data'] = '';
300
+ }
301
+ return $header;
302
+ }
303
+ }
304
+ return false;
305
+ }
306
+
307
+ /**
308
+ * Pack file to TAR (Tape Archiver).
309
+ *
310
+ * @param string $source
311
+ * @param string $destination
312
+ * @param boolean $skipRoot
313
+ * @return string
314
+ */
315
+ public function pack($source, $destination, $skipRoot=false)
316
+ {
317
+ $this->_setSkipRoot($skipRoot);
318
+ $source = realpath($source);
319
+ $tarData = $this->_setCurrentPath($source)
320
+ ->_setCurrentFile($source)
321
+ ->_packToTar($skipRoot);
322
+ $this->_writeFile($destination, $tarData);
323
+ return $destination;
324
+ }
325
+
326
+ /**
327
+ * Unpack file from TAR (Tape Archiver).
328
+ *
329
+ * @param string $source
330
+ * @param string $destination
331
+ * @return string
332
+ */
333
+ public function unpack($source, $destination)
334
+ {
335
+ $tempFile = $destination . DS . '~tmp-'.microtime(true).'.tar';
336
+ $data = $this->_readFile($source);
337
+ $this->_writeFile($tempFile, $data);
338
+ $this->_setCurrentFile($tempFile)
339
+ ->_setCurrentPath($tempFile)
340
+ ->_unpackCurrentTar($destination);
341
+ unlink($tempFile);
342
+ return $destination;
343
+ }
344
+
345
+ /**
346
+ * Extract one file from TAR (Tape Archiver).
347
+ *
348
+ * @param string $file
349
+ * @param string $source
350
+ * @param string $destination
351
+ * @return string
352
+ */
353
+ public function extract($file, $source, $destination)
354
+ {
355
+ $pointer = fopen($source, 'r');
356
+ if (empty($pointer)) {
357
+ throw new Mage_Exception('Can\'t open file: '.$source);
358
+ }
359
+ $list = array();
360
+ $extractedFile = '';
361
+ while (!feof($pointer)) {
362
+ $header = $this->_parseHeader($pointer);
363
+ if ($header['name'] == $file) {
364
+ $extractedFile = $destination . basename($header['name']);
365
+ $this->_writeFile($extractedFile, $header['data']);
366
+ break;
367
+ }
368
+ }
369
+ fclose($pointer);
370
+ return $extractedFile;
371
+ }
372
+ }
downloader/lib/Mage/Autoload/Simple.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Autoload
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ class Mage_Autoload_Simple
28
+ {
29
+ private static $_instance;
30
+
31
+ public static function instance()
32
+ {
33
+ if (!self::$_instance) {
34
+ $class = __CLASS__;
35
+ self::$_instance = new $class();
36
+ }
37
+ return self::$_instance;
38
+ }
39
+
40
+ public static function register()
41
+ {
42
+ spl_autoload_register(array(self::instance(), 'autoload'));
43
+ }
44
+
45
+ public function autoload($class)
46
+ {
47
+ $classFile = str_replace(' ', DIRECTORY_SEPARATOR, ucwords(str_replace('_', ' ', $class)));
48
+ $classFile.= '.php';
49
+ @include $classFile;
50
+ }
51
+
52
+ }
downloader/lib/Mage/Connect/Channel/Generator.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ class Mage_Connect_Channel_Generator extends Mage_Xml_Generator
28
+ {
29
+ protected $_file = 'channel.xml';
30
+ protected $_generator = null;
31
+
32
+ public function __construct($file='')
33
+ {
34
+ if ($file) {
35
+ $this->_file = $file;
36
+ }
37
+ return $this;
38
+ }
39
+
40
+ public function getFile()
41
+ {
42
+ return $this->_file;
43
+ }
44
+
45
+ public function getGenerator()
46
+ {
47
+ if (is_null($this->_generator)) {
48
+ $this->_generator = new Mage_Xml_Generator();
49
+ }
50
+ return $this->_generator;
51
+ }
52
+
53
+ /**
54
+ * @param array $content
55
+ */
56
+ public function save($content)
57
+ {
58
+ $xmlContent = $this->getGenerator()
59
+ ->arrayToXml($content)
60
+ ->save($this->getFile());
61
+ return $this;
62
+ }
63
+ }
downloader/lib/Mage/Connect/Channel/Parser.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
downloader/lib/Mage/Connect/Channel/VO.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+
28
+ class Mage_Connect_Channel_VO implements Iterator
29
+ {
30
+
31
+ private $_validator = null;
32
+
33
+ protected $properties = array(
34
+ 'name' => '',
35
+ 'uri' => '',
36
+ 'summary' => '',
37
+ );
38
+
39
+ public function rewind() {
40
+ reset($this->properties);
41
+ }
42
+
43
+ public function valid() {
44
+ return current($this->properties) !== false;
45
+ }
46
+
47
+ public function key() {
48
+ return key($this->properties);
49
+ }
50
+
51
+ public function current() {
52
+ return current($this->properties);
53
+ }
54
+
55
+ public function next() {
56
+ next($this->properties);
57
+ }
58
+
59
+ public function __get($var)
60
+ {
61
+ if (isset($this->properties[$var])) {
62
+ return $this->properties[$var];
63
+ }
64
+ return null;
65
+ }
66
+
67
+ public function __set($var, $value)
68
+ {
69
+ if (is_string($value)) {
70
+ $value = trim($value);
71
+ }
72
+ if (isset($this->properties[$var])) {
73
+ if ($value === null) {
74
+ $value = '';
75
+ }
76
+ $this->properties[$var] = $value;
77
+ }
78
+ }
79
+
80
+ public function toArray()
81
+ {
82
+ return array('channel' => $this->properties);
83
+ }
84
+
85
+ public function fromArray(array $arr)
86
+ {
87
+ foreach($arr as $k=>$v) {
88
+ $this->$k = $v;
89
+ }
90
+ }
91
+
92
+
93
+ private function validator()
94
+ {
95
+ if(is_null($this->_validator)) {
96
+ $this->_validator = new Mage_Connect_Validator();
97
+ }
98
+ return $this->_validator;
99
+ }
100
+
101
+ /**
102
+ Stub for validation result
103
+ */
104
+ public function validate()
105
+ {
106
+ $v = $this->validator();
107
+ if(!$v->validatePackageName($this->name)) {
108
+ return false;
109
+ }
110
+ return true;
111
+ }
112
+
113
+ }
downloader/lib/Mage/Connect/Command.php ADDED
@@ -0,0 +1,390 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+
28
+ class Mage_Connect_Command
29
+ {
30
+ /**
31
+ * All commands list
32
+ * @var array
33
+ */
34
+ protected static $_commandsAll = array();
35
+
36
+ /**
37
+ * Commands list hash (key=class)
38
+ * @var array
39
+ */
40
+ protected static $_commandsByClass = array();
41
+
42
+ /**
43
+ * Frontend object
44
+ * @var Mage_Connect_Fro
45
+ */
46
+ protected static $_frontend = null;
47
+ protected static $_config = null;
48
+ protected static $_registry = null;
49
+ protected static $_validator = null;
50
+ protected static $_rest = null;
51
+ protected static $_sconfig = null;
52
+
53
+ protected $_data;
54
+ protected $_class;
55
+ protected static $_packager = null;
56
+
57
+ protected static $_return = array();
58
+
59
+ /**
60
+ * Constructor
61
+ *
62
+ */
63
+ public function __construct()
64
+ {
65
+ $class = $this->_class = get_class($this);
66
+ if(__CLASS__ == $class) {
67
+ throw new Exception("You shouldn't instantiate {$class} directly!");
68
+ }
69
+ $this->commandsInfo = self::$_commandsByClass[$class];
70
+ }
71
+
72
+
73
+ /**
74
+ * Get command info (static)
75
+ * @param string $name command name
76
+ * @return array/bool
77
+ */
78
+ public static function commandInfo($name)
79
+ {
80
+ $name = strtolower($name);
81
+ if(!isset(self::$_commandsAll[$name])) {
82
+ return false;
83
+ }
84
+ return self::$_commandsAll[$name];
85
+ }
86
+
87
+ /**
88
+ * Get command info for current command object
89
+ * @param string $name
90
+ * @return array/bool
91
+ */
92
+
93
+ public function getCommandInfo($name)
94
+ {
95
+ if(!isset(self::$_commandsByClass[$this->_class][$name])) {
96
+ return false;
97
+ }
98
+ return self::$_commandsByClass[$this->_class][$name];
99
+ }
100
+
101
+ /**
102
+ * Run command
103
+ * @param string $command
104
+ * @param string $options
105
+ * @param string $params
106
+ * @throws Exception if there's no needed method
107
+ * @return mixed
108
+ */
109
+ public function run($command, $options, $params)
110
+ {
111
+ $data = $this->getCommandInfo($command);
112
+ $method = $data['function'];
113
+ if(! method_exists($this, $method)) {
114
+ throw new Exception("$method does't exist in class ".$this->_class);
115
+ }
116
+ return $this->$method($command, $options, $params);
117
+ }
118
+
119
+ /**
120
+ * Static functions
121
+ */
122
+
123
+ /**
124
+ * Static
125
+ * @param $commandName
126
+ * @return unknown_type
127
+ */
128
+ public static function getInstance($commandName)
129
+ {
130
+ if(!isset(self::$_commandsAll[$commandName])) {
131
+ throw new UnexpectedValueException("Cannot find command $commandName");
132
+ }
133
+ $currentCommand = self::$_commandsAll[$commandName];
134
+ return new $currentCommand['class']();
135
+ }
136
+
137
+
138
+ public static function setSconfig($obj)
139
+ {
140
+ self::$_sconfig = $obj;
141
+ }
142
+
143
+ /**
144
+ *
145
+ * @return Mage_Connect_Singleconfig
146
+ */
147
+ public function getSconfig()
148
+ {
149
+ return self::$_sconfig;
150
+ }
151
+
152
+
153
+ /**
154
+ * Sets frontend object for all commands
155
+ *
156
+ * @param Mage_Connect_Frontend $obj
157
+ * @return void
158
+ */
159
+ public static function setFrontendObject($obj)
160
+ {
161
+ self::$_frontend = $obj;
162
+ }
163
+
164
+
165
+ /**
166
+ * Set config object for all commands
167
+ * @param Mage_Connect_Config $obj
168
+ * @return void
169
+ */
170
+ public static function setConfigObject($obj)
171
+ {
172
+ self::$_config = $obj;
173
+ }
174
+
175
+
176
+ /**
177
+ * Non-static getter for config
178
+ * @return Mage_Connect_Config
179
+ */
180
+ public function config()
181
+ {
182
+ return self::$_config;
183
+ }
184
+
185
+ /**
186
+ * Non-static getter for UI
187
+ * @return Mage_Connect_Frontend
188
+ */
189
+ public function ui()
190
+ {
191
+ return self::$_frontend;
192
+ }
193
+
194
+
195
+ /**
196
+ * Get validator object
197
+ * @return Mage_Connect_Validator
198
+ */
199
+ public function validator()
200
+ {
201
+ if(is_null(self::$_validator)) {
202
+ self::$_validator = new Mage_Connect_Validator();
203
+ }
204
+ return self::$_validator;
205
+ }
206
+
207
+ /**
208
+ * Get rest object
209
+ * @return Mage_Connect_Rest
210
+ */
211
+ public function rest()
212
+ {
213
+ if(is_null(self::$_rest)) {
214
+ self::$_rest = new Mage_Connect_Rest(self::config()->protocol);
215
+ }
216
+ return self::$_rest;
217
+ }
218
+
219
+
220
+ /**
221
+ * Get commands list sorted
222
+ * @return array
223
+ */
224
+ public static function getCommands()
225
+ {
226
+ if(!count(self::$_commandsAll)) {
227
+ self::registerCommands();
228
+ }
229
+ ksort(self::$_commandsAll);
230
+ return self::$_commandsAll;
231
+ }
232
+
233
+
234
+ /**
235
+ * Get Getopt args from command definitions
236
+ * and parse them
237
+ * @param $command
238
+ * @return array
239
+ */
240
+ public static function getGetoptArgs($command)
241
+ {
242
+ $commandInfo = self::commandInfo($command);
243
+ $short_args = '';
244
+ $long_args = array();
245
+ if (empty($commandInfo) || empty($commandInfo['options'])) {
246
+ return;
247
+ }
248
+ reset($commandInfo['options']);
249
+ while (list($option, $info) = each($commandInfo['options'])) {
250
+ $larg = $sarg = '';
251
+ if (isset($info['arg'])) {
252
+ if ($info['arg']{0} == '(') {
253
+ $larg = '==';
254
+ $sarg = '::';
255
+ $arg = substr($info['arg'], 1, -1);
256
+ } else {
257
+ $larg = '=';
258
+ $sarg = ':';
259
+ $arg = $info['arg'];
260
+ }
261
+ }
262
+ if (isset($info['shortopt'])) {
263
+ $short_args .= $info['shortopt'] . $sarg;
264
+ }
265
+ $long_args[] = $option . $larg;
266
+ }
267
+ return array($short_args, $long_args);
268
+ }
269
+
270
+ /**
271
+ * Try to register commands automatically
272
+ * @return void
273
+ */
274
+ public static function registerCommands()
275
+ {
276
+ $pathCommands = dirname(__FILE__).DIRECTORY_SEPARATOR.basename(__FILE__, ".php");
277
+ $f = new DirectoryIterator($pathCommands);
278
+ foreach($f as $file) {
279
+ if (! $file->isFile()) {
280
+ continue;
281
+ }
282
+ $pattern = preg_match("/(.*)_Header\.php/imsu", $file->getFilename(), $matches);
283
+ if(! $pattern) {
284
+ continue;
285
+ }
286
+ include($file->getPathname());
287
+ if(! isset($commands)) {
288
+ continue;
289
+ }
290
+ $class = __CLASS__."_".$matches[1];
291
+ foreach ($commands as $k=>$v) {
292
+ $commands[$k]['class'] = $class;
293
+ self::$_commandsAll[$k] = $commands[$k];
294
+ }
295
+ self::$_commandsByClass[$class] = $commands;
296
+ }
297
+ }
298
+
299
+ public function doError($command, $message)
300
+ {
301
+ return $this->ui()->doError($command, $message);
302
+ }
303
+
304
+
305
+ /**
306
+ * Set command return
307
+ * @param string $key
308
+ * @param mixed $val
309
+ * @return void
310
+ */
311
+ public static function setReturn($key, $val)
312
+ {
313
+ self::$_return[$key] = $val;
314
+ }
315
+
316
+ /**
317
+ * Get command return
318
+ * @param $key
319
+ * @param $clear
320
+ * @return mixed
321
+ */
322
+ public static function getReturn($key, $clear = true)
323
+ {
324
+ if(isset(self::$_return[$key])) {
325
+ $out = self::$_return[$key];
326
+ if($clear) {
327
+ unset(self::$_return[$key]);
328
+ }
329
+ return $out;
330
+ }
331
+ return null;
332
+ }
333
+
334
+ /**
335
+ * Cleanup command params from empty strings
336
+ *
337
+ * @param array $params by reference
338
+ */
339
+ public function cleanupParams(array & $params)
340
+ {
341
+ $newParams = array();
342
+ if(!count($params)) {
343
+ return;
344
+ }
345
+ foreach($params as $k=>$v) {
346
+ if(is_string($v)) {
347
+ $v = trim($v);
348
+ if(!strlen($v)) {
349
+ continue;
350
+ }
351
+ }
352
+ $newParams[] = $v;
353
+ }
354
+ $params = $newParams;
355
+ }
356
+
357
+ /**
358
+ * Splits first command argument: channel/package
359
+ * to two arguments if found in top of array
360
+ *
361
+ * @param array $params
362
+ */
363
+ public function splitPackageArgs(array & $params)
364
+ {
365
+ if(!count($params) || !isset($params[0])) {
366
+ return;
367
+ }
368
+ if($this->validator()->validateUrl($params[0])) {
369
+ return;
370
+ }
371
+ if(preg_match("@([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)@ims", $params[0], $subs)) {
372
+ $params[0] = $subs[2];
373
+ array_unshift($params, $subs[1]);
374
+ }
375
+ }
376
+
377
+
378
+ /**
379
+ * Get packager instance
380
+ * @return Mage_Connect_Pacakger
381
+ */
382
+ public function getPackager()
383
+ {
384
+ if(!self::$_packager) {
385
+ self::$_packager = new Mage_Connect_Packager();
386
+ }
387
+ return self::$_packager;
388
+ }
389
+
390
+ }
downloader/lib/Mage/Connect/Command/Channels.php ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ final class Mage_Connect_Command_Channels
28
+ extends Mage_Connect_Command
29
+ {
30
+
31
+ /**
32
+ * List available channels
33
+ * @param $command
34
+ * @param $params
35
+ * @param $options
36
+ */
37
+ public function doList($command, $options, $params)
38
+ {
39
+
40
+ try {
41
+ $title = "Available channels:";
42
+ $aliasT = "Available aliases:";
43
+ $packager = $this->getPackager();
44
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
45
+ if($ftp) {
46
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
47
+ $data = $cache->getData();
48
+ @unlink($config->getFilename());
49
+ @unlink($cache->getFilename());
50
+ } else {
51
+ $cache = $this->getSconfig();
52
+ $config = $this->config();
53
+ $data = $cache->getData();
54
+ }
55
+ $out = array($command => array('data'=>$data, 'title'=>$title, 'title_aliases'=>$aliasT));
56
+ $this->ui()->output($out);
57
+ } catch (Exception $e) {
58
+ $this->doError($command, $e->getMessage());
59
+ }
60
+ }
61
+
62
+ /**
63
+ * channel-delete callback method
64
+ * @param string $command
65
+ * @param array $options
66
+ * @param array $params
67
+ */
68
+ public function doDelete($command, $options, $params)
69
+ {
70
+ $this->cleanupParams($params);
71
+ try {
72
+ if(count($params) != 1) {
73
+ throw new Exception("Parameters count should be equal to 1");
74
+ }
75
+ $packager = $this->getPackager();
76
+
77
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
78
+ if($ftp) {
79
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
80
+ $cache->deleteChannel($params[0]);
81
+ $packager->writeToRemoteCache($cache, $ftpObj);
82
+ @unlink($config->getFilename());
83
+ } else {
84
+ $config = $this->config();
85
+ $cache = $this->getSconfig();
86
+ $cache->deleteChannel($params[0]);
87
+ }
88
+ $this->ui()->output("Successfully deleted");
89
+
90
+ } catch (Exception $e) {
91
+ $this->doError($command, $e->getMessage());
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Channel-add callback
97
+ * @param string $command
98
+ * @param array $options
99
+ * @param array $params
100
+ */
101
+ public function doAdd($command, $options, $params)
102
+ {
103
+ $this->cleanupParams($params);
104
+ try {
105
+ if(count($params) != 1) {
106
+ throw new Exception("Parameters count should be equal to 1");
107
+ }
108
+ $url = $params[0];
109
+ $rest = $this->rest();
110
+ $rest->setChannel($url);
111
+ $data = $rest->getChannelInfo();
112
+ $data->url = $url;
113
+
114
+ $packager = $this->getPackager();
115
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
116
+ if($ftp) {
117
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
118
+ $cache->addChannel($data->name, $url);
119
+ $packager->writeToRemoteCache($cache, $ftpObj);
120
+ @unlink($config->getFilename());
121
+ } else {
122
+ $cache = $this->getSconfig();
123
+ $config = $this->config();
124
+ $cache->addChannel($data->name, $url);
125
+ }
126
+
127
+ $this->ui()->output("Successfully added: ".$url);
128
+ } catch (Exception $e) {
129
+ $this->doError($command, $e->getMessage());
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Get information about given channel callback
135
+ * @param string $command
136
+ * @param array $options
137
+ * @param array $params
138
+ */
139
+ public function doInfo($command, $options, $params)
140
+ {
141
+
142
+ }
143
+
144
+ /**
145
+ * channel-alias
146
+ * @param $command
147
+ * @param $options
148
+ * @param $params
149
+ * @return unknown_type
150
+ */
151
+ public function doAlias($command, $options, $params)
152
+ {
153
+ $this->cleanupParams($params);
154
+ try {
155
+ if(count($params) != 2) {
156
+ throw new Exception("Parameters count should be equal to 2");
157
+ }
158
+
159
+ $packager = $this->getPackager();
160
+ $chanUrl = $params[0];
161
+ $alias = $params[1];
162
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
163
+ if($ftp) {
164
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
165
+ $cache->addChannelAlias($chanUrl, $alias);
166
+ $packager->writeToRemoteCache($cache, $ftpObj);
167
+ @unlink($config->getFilename());
168
+ } else {
169
+ $cache = $this->getSconfig();
170
+ $config = $this->config();
171
+ $cache->addChannelAlias($chanUrl, $alias);
172
+ }
173
+ $this->ui()->output("Successfully added: ".$alias);
174
+ } catch (Exception $e) {
175
+ $this->doError($command, $e->getMessage());
176
+ }
177
+ }
178
+
179
+ public function doLogin($command, $options, $params)
180
+ {
181
+
182
+ }
183
+
184
+ public function doLogout($command, $options, $params)
185
+ {
186
+
187
+ }
188
+
189
+ }
downloader/lib/Mage/Connect/Command/Channels_Header.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ $commands = array(
28
+ 'list-channels' => array(
29
+ 'summary' => 'List Available Channels',
30
+ 'function' => 'doList',
31
+ 'shortcut' => 'lc',
32
+ 'options' => array(),
33
+ 'doc' => '
34
+ List all available channels for installation.
35
+ ',
36
+ ),
37
+ 'channel-delete' => array(
38
+ 'summary' => 'Remove a Channel From the List',
39
+ 'function' => 'doDelete',
40
+ 'shortcut' => 'cde',
41
+ 'options' => array(),
42
+ 'doc' => '<channel name>
43
+ Delete a channel from the registry. You may not
44
+ remove any channel that has installed packages.
45
+ '
46
+ ),
47
+ 'channel-add' => array(
48
+ 'summary' => 'Add a Channel',
49
+ 'function' => 'doAdd',
50
+ 'shortcut' => 'ca',
51
+ 'options' => array(),
52
+ 'doc' => '<channel.xml>
53
+ Add a private channel to the channel list. Note that all
54
+ public channels should be synced using "update-channels".
55
+ Parameter may be either a local file or remote URL to a
56
+ channel.xml.
57
+ '
58
+ ),
59
+ 'channel-info' => array(
60
+ 'summary' => 'Retrieve Information on a Channel',
61
+ 'function' => 'doInfo',
62
+ 'shortcut' => 'ci',
63
+ 'options' => array(),
64
+ 'doc' => '<package>
65
+ List the files in an installed package.
66
+ '
67
+ ),
68
+ 'channel-alias' => array(
69
+ 'summary' => 'Specify an alias to a channel name',
70
+ 'function' => 'doAlias',
71
+ 'shortcut' => 'cha',
72
+ 'options' => array(),
73
+ 'doc' => '<channel> <alias>
74
+ Specify a specific alias to use for a channel name.
75
+ The alias may not be an existing channel name or
76
+ alias.
77
+ '
78
+ ),
79
+ 'channel-login' => array(
80
+ 'summary' => 'Connects and authenticates to remote channel server',
81
+ 'shortcut' => 'cli',
82
+ 'function' => 'doLogin',
83
+ 'options' => array(),
84
+ 'doc' => '<channel name>
85
+ Log in to a remote channel server. If <channel name> is not supplied,
86
+ the default channel is used. To use remote functions in the installer
87
+ that require any kind of privileges, you need to log in first. The
88
+ username and password you enter here will be stored in your per-user
89
+ PEAR configuration (~/.pearrc on Unix-like systems). After logging
90
+ in, your username and password will be sent along in subsequent
91
+ operations on the remote server.',
92
+ ),
93
+ 'channel-logout' => array(
94
+ 'summary' => 'Logs out from the remote channel server',
95
+ 'shortcut' => 'clo',
96
+ 'function' => 'doLogout',
97
+ 'options' => array(),
98
+ 'doc' => '<channel name>
99
+ Logs out from a remote channel server. If <channel name> is not supplied,
100
+ the default channel is used. This command does not actually connect to the
101
+ remote server, it only deletes the stored username and password from your user
102
+ configuration.',
103
+ ),
104
+ );
downloader/lib/Mage/Connect/Command/Config.php ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+
28
+ class Mage_Connect_Command_Config
29
+ extends Mage_Connect_Command
30
+
31
+ {
32
+ const PARAM_KEY = 0;
33
+ const PARAM_VAL = 1;
34
+
35
+
36
+ /**
37
+ * Show config variable
38
+ * @param string $command
39
+ * @param array $options
40
+ * @param array $params
41
+ * @return void
42
+ */
43
+ public function doConfigShow($command, $options, $params)
44
+ {
45
+ $this->cleanupParams($params);
46
+
47
+ try {
48
+ $values = array();
49
+
50
+ $packager = $this->getPackager();
51
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
52
+ if($ftp) {
53
+ list($config, $ftpObj) = $packager->getRemoteConfig($ftp);
54
+ } else {
55
+ $config = $this->config();
56
+ }
57
+ foreach( $config as $k=>$v ) {
58
+ $values[$k] = $v;
59
+ }
60
+ if($ftp) {
61
+ @unlink($config->getFilename());
62
+ }
63
+ $data = array($command => array('data'=>$values));
64
+ $this->ui()->output($data);
65
+ } catch (Exception $e) {
66
+ if($ftp) {
67
+ @unlink($config->getFilename());
68
+ }
69
+ return $this->doError($command, $e->getMessage());
70
+ }
71
+ }
72
+
73
+
74
+ /**
75
+ * Set config variable
76
+ * @param string $command
77
+ * @param array $options
78
+ * @param array $params
79
+ * @return void
80
+ */
81
+ public function doConfigSet($command, $options, $params)
82
+ {
83
+ $this->cleanupParams($params);
84
+
85
+ try {
86
+ if(count($params) < 2) {
87
+ throw new Exception("Parameters count should be >= 2");
88
+ }
89
+ $key = strtolower($params[self::PARAM_KEY]);
90
+ $val = strval($params[self::PARAM_VAL]);
91
+ $packager = $this->getPackager();
92
+
93
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
94
+ if(!$ftp) {
95
+ $config = $this->config();
96
+ $ftp=$config->remote_config;
97
+ }
98
+ if($ftp) {
99
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
100
+ }
101
+
102
+ if(!$config->hasKey($key)) {
103
+ throw new Exception ("No such config variable: {$key}!");
104
+ }
105
+ if(!$config->validate($key, $val)) {
106
+ $possible = $this->config()->possible($key);
107
+ $type = $this->config()->type($key);
108
+ $errString = "Invalid value specified for $key!";
109
+ throw new Exception($errString);
110
+ }
111
+ if($ftp) {
112
+ $packager->writeToRemoteConfig($config, $ftpObj);
113
+ }
114
+ $this->config()->$key = $val;
115
+ $this->ui()->output('Success');
116
+ } catch (Exception $e) {
117
+ if($ftp) {
118
+ @unlink($config->getFilename());
119
+ }
120
+ return $this->doError($command, $e->getMessage());
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Get config var
126
+ * @param string $command
127
+ * @param array $options
128
+ * @param array $params
129
+ * @return void
130
+ */
131
+ public function doConfigGet($command, $options, $params)
132
+ {
133
+ $this->cleanupParams($params);
134
+
135
+ try {
136
+ if(count($params) < 1) {
137
+ throw new Exception("Parameters count should be >= 1");
138
+ }
139
+ $packager = $this->getPackager();
140
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
141
+ if($ftp) {
142
+ list($config, $ftpObj) = $packager->getRemoteConfig($ftp);
143
+ } else {
144
+ $config = $this->config();
145
+ }
146
+ $key = strtolower($params[self::PARAM_KEY]);
147
+ if(!$config->hasKey($key)) {
148
+ throw new Exception("No such config variable '{$key}'!");
149
+ }
150
+ if($ftp) {
151
+ @unlink($config->getFilename());
152
+ }
153
+ $this->ui()->output($config->$key);
154
+ } catch (Exception $e) {
155
+ if($ftp) {
156
+ @unlink($config->getFilename());
157
+ }
158
+ return $this->doError($command, $e->getMessage());
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Config help
164
+ * @param string $command
165
+ * @param array $options
166
+ * @param array $params
167
+ * @return void
168
+ */
169
+ public function doConfigHelp($command, $options, $params)
170
+ {
171
+ try {
172
+ $this->cleanupParams($params);
173
+ if(count($params) < 1) {
174
+ throw new Exception( "Parameters count should be >= 1");
175
+ }
176
+ $packager = $this->getPackager();
177
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
178
+ if($ftp) {
179
+ list($config, $ftpObj) = $packager->getRemoteConfig($ftp);
180
+ } else {
181
+ $config = $this->config();
182
+ }
183
+
184
+ $key = strtolower($params[self::PARAM_KEY]);
185
+ if(!$this->config()->hasKey($key)) {
186
+ throw new Exception("No such config variable '{$key}'!");
187
+ }
188
+
189
+ $possible = $config->possible($key);
190
+ $type = $config->type($key);
191
+ $doc = $config->doc($key);
192
+ if($ftp) {
193
+ @unlink($config->getFilename());
194
+ }
195
+ $data = array();
196
+ $data[$command]['data'] = array(
197
+ 'name' => array('Variable name', $key),
198
+ 'type' => array('Value type', $type),
199
+ 'possible' => array('Possible values', $possible),
200
+ 'doc' => $doc,
201
+ );
202
+ $this->ui()->output($data);
203
+ } catch (Exception $e) {
204
+ if($ftp) {
205
+ @unlink($config->getFilename());
206
+ }
207
+ return $this->doError($command, $e->getMessage());
208
+ }
209
+ }
210
+
211
+ }
212
+
213
+
downloader/lib/Mage/Connect/Command/Config_Header.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ $commands = array(
28
+ 'config-show' => array(
29
+ 'summary' => 'Show All Settings',
30
+ 'function' => 'doConfigShow',
31
+ 'shortcut' => 'csh',
32
+ 'options' => array(
33
+ 'channel' => array(
34
+ 'shortopt' => 'c',
35
+ 'doc' => 'show configuration variables for another channel',
36
+ 'arg' => 'CHAN',
37
+ ),
38
+ ),
39
+ 'doc' => '[layer]
40
+ Displays all configuration values. An optional argument
41
+ may be used to tell which configuration layer to display. Valid
42
+ configuration layers are "user", "system" and "default". To display
43
+ configurations for different channels, set the default_channel
44
+ configuration variable and run config-show again.
45
+ ',
46
+ ),
47
+ 'config-get' => array(
48
+ 'summary' => 'Show One Setting',
49
+ 'function' => 'doConfigGet',
50
+ 'shortcut' => 'cg',
51
+ 'options' => array(
52
+ 'channel' => array(
53
+ 'shortopt' => 'c',
54
+ 'doc' => 'show configuration variables for another channel',
55
+ 'arg' => 'CHAN',
56
+ ),
57
+ ),
58
+ 'doc' => '<parameter> [layer]
59
+ Displays the value of one configuration parameter. The
60
+ first argument is the name of the parameter, an optional second argument
61
+ may be used to tell which configuration layer to look in. Valid configuration
62
+ layers are "user", "system" and "default". If no layer is specified, a value
63
+ will be picked from the first layer that defines the parameter, in the order
64
+ just specified. The configuration value will be retrieved for the channel
65
+ specified by the default_channel configuration variable.
66
+ ',
67
+ ),
68
+ 'config-set' => array(
69
+ 'summary' => 'Change Setting',
70
+ 'function' => 'doConfigSet',
71
+ 'shortcut' => 'cs',
72
+ 'options' => array(
73
+ 'channel' => array(
74
+ 'shortopt' => 'c',
75
+ 'doc' => 'show configuration variables for another channel',
76
+ 'arg' => 'CHAN',
77
+ ),
78
+ ),
79
+ 'doc' => '<parameter> <value> [layer]
80
+ Sets the value of one configuration parameter. The first argument is
81
+ the name of the parameter, the second argument is the new value. Some
82
+ parameters are subject to validation, and the command will fail with
83
+ an error message if the new value does not make sense. An optional
84
+ third argument may be used to specify in which layer to set the
85
+ configuration parameter. The default layer is "user". The
86
+ configuration value will be set for the current channel, which
87
+ is controlled by the default_channel configuration variable.
88
+ ',
89
+ ),
90
+ 'config-help' => array(
91
+ 'summary' => 'Show Information About Setting',
92
+ 'function' => 'doConfigHelp',
93
+ 'shortcut' => 'ch',
94
+ 'options' => array(),
95
+ 'doc' => '[parameter]
96
+ Displays help for a configuration parameter. Without arguments it
97
+ displays help for all configuration parameters.
98
+ ',
99
+ ),
100
+ );
downloader/lib/Mage/Connect/Command/Install.php ADDED
@@ -0,0 +1,567 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+
28
+ final class Mage_Connect_Command_Install
29
+ extends Mage_Connect_Command
30
+ {
31
+
32
+ /**
33
+ * Install action callback
34
+ * @param string $command
35
+ * @param array $options
36
+ * @param array $params
37
+ * @return void
38
+ */
39
+ public function doInstall($command, $options, $params, $objects = array())
40
+ {
41
+ $this->cleanupParams($params);
42
+
43
+ $installFileMode = $command === 'install-file';
44
+
45
+
46
+ $cache=null;
47
+ /**
48
+ * @var $cache Mage_Connect_Singleconfig
49
+ */
50
+ $ftpObj=null;
51
+
52
+
53
+ try {
54
+ $packager = $this->getPackager();
55
+ $forceMode = isset($options['force']);
56
+ $upgradeAllMode = $command == 'upgrade-all';
57
+ $upgradeMode = $command == 'upgrade' || $command == 'upgrade-all';
58
+ $noFilesInstall = isset($options['nofiles']);
59
+ $withDepsMode = !isset($options['nodeps']);
60
+ $ignoreModifiedMode = true || !isset($options['ignorelocalmodification']);
61
+ $clearInstallMode = $command == 'install' && !$forceMode;
62
+ $installAll = isset($options['install_all']);
63
+ $channelAuth = isset($options['auth'])?$options['auth']:array();
64
+
65
+ $rest = $this->rest();
66
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
67
+ if($ftp) {
68
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
69
+ } else {
70
+ $config = $this->config();
71
+ $cache = $this->getSconfig();
72
+ }
73
+ if(empty($config->magento_root)){
74
+ $config->magento_root=dirname(dirname($_SERVER['SCRIPT_FILENAME']));
75
+ }
76
+ chdir($config->magento_root);
77
+ $dirCache = DIRECTORY_SEPARATOR . $config->downloader_path . DIRECTORY_SEPARATOR
78
+ . Mage_Connect_Config::DEFAULT_CACHE_PATH;
79
+ $dirTmp = DIRECTORY_SEPARATOR . Mage_Connect_Package_Reader::PATH_TO_TEMPORARY_DIRECTORY;
80
+ $dirMedia = DIRECTORY_SEPARATOR . 'media';
81
+ $isWritable = true;
82
+ if($ftp) {
83
+ $cwd=$ftpObj->getcwd();
84
+ $ftpObj->mkdirRecursive($cwd . $dirCache,0777);
85
+ $ftpObj->chdir($cwd);
86
+ $ftpObj->mkdirRecursive($cwd . $dirTmp,0777);
87
+ $ftpObj->chdir($cwd);
88
+ $ftpObj->mkdirRecursive($cwd . $dirMedia,0777);
89
+ $ftpObj->chdir($cwd);
90
+ $err = "Please check for sufficient ftp write file permissions.";
91
+ } else {
92
+ @mkdir($config->magento_root . $dirCache,0777,true);
93
+ @mkdir($config->magento_root . $dirTmp,0777,true);
94
+ @mkdir($config->magento_root . $dirMedia,0777,true);
95
+ $isWritable = is_writable($config->magento_root)
96
+ && is_writable($config->magento_root . DIRECTORY_SEPARATOR . $config->downloader_path)
97
+ && is_writable($config->magento_root . $dirCache)
98
+ && is_writable($config->magento_root . $dirTmp)
99
+ && is_writable($config->magento_root . $dirMedia);
100
+ $err = "Please check for sufficient write file permissions.";
101
+ }
102
+ $isWritable = $isWritable && is_writable($config->magento_root . $dirMedia)
103
+ && is_writable($config->magento_root . $dirCache)
104
+ && is_writable($config->magento_root . $dirTmp);
105
+ if(!$isWritable){
106
+ $this->doError($command, $err);
107
+ throw new Exception(
108
+ 'Your Magento folder does not have sufficient write permissions, which downloader requires.'
109
+ );
110
+ }
111
+ if(!empty($channelAuth)){
112
+ $rest->getLoader()->setCredentials($channelAuth['username'], $channelAuth['password']);
113
+ }
114
+
115
+ if($installFileMode) {
116
+ if(count($params) < 1) {
117
+ throw new Exception("Argument should be: filename");
118
+ }
119
+ $filename = $params[0];
120
+ if(!@file_exists($filename)) {
121
+ throw new Exception("File '{$filename}' not found");
122
+ }
123
+ if(!@is_readable($filename)) {
124
+ throw new Exception("File '{$filename}' is not readable");
125
+ }
126
+
127
+ $package = new Mage_Connect_Package($filename);
128
+ $package->setConfig($config);
129
+ $package->validate();
130
+ $errors = $package->getErrors();
131
+ if(count($errors)) {
132
+ throw new Exception("Package file is invalid\n".implode("\n", $errors));
133
+ }
134
+
135
+ $pChan = $package->getChannel();
136
+ $pName = $package->getName();
137
+ $pVer = $package->getVersion();
138
+
139
+
140
+ if (!($cache->isChannelName($pChan) || $cache->isChannelAlias($pChan))) {
141
+ throw new Exception("The '{$pChan}' channel is not installed. Please use the MAGE shell "
142
+ . "script to install the '{$pChan}' channel.");
143
+ }
144
+
145
+ $conflicts = $cache->hasConflicts($pChan, $pName, $pVer);
146
+
147
+ if(false !== $conflicts) {
148
+ $conflicts = implode(", ",$conflicts);
149
+ if($forceMode) {
150
+ $this->doError($command, "Package {$pChan}/{$pName} {$pVer} conflicts with: ".$conflicts);
151
+ } else {
152
+ throw new Exception("Package {$pChan}/{$pName} {$pVer} conflicts with: ".$conflicts);
153
+ }
154
+ }
155
+
156
+ $conflicts = $package->checkPhpDependencies();
157
+ if(true !== $conflicts) {
158
+ $confilcts = implode(",",$conflicts);
159
+ $err = "Package {$pChan}/{$pName} {$pVer} depends on PHP extensions: ".$conflicts;
160
+ if($forceMode) {
161
+ $this->doError($command, $err);
162
+ } else {
163
+ throw new Exception($err);
164
+ }
165
+ }
166
+
167
+ $conflicts = $package->checkPhpVersion();
168
+ if(true !== $conflicts) {
169
+ $err = "Package {$pChan}/{$pName} {$pVer}: ".$conflicts;
170
+ if($forceMode) {
171
+ $this->doError($command, $err);
172
+ } else {
173
+ throw new Exception($err);
174
+ }
175
+ }
176
+
177
+
178
+ if(!$noFilesInstall) {
179
+ if($ftp) {
180
+ $packager->processInstallPackageFtp($package, $filename, $config, $ftpObj);
181
+ } else {
182
+ $packager->processInstallPackage($package, $filename, $config);
183
+ }
184
+ }
185
+ $cache->addPackage($package);
186
+ $installedDeps = array();
187
+ $installedDepsAssoc = array();
188
+ $installedDepsAssoc[] = array('channel'=>$pChan, 'name'=>$pName, 'version'=>$pVer);
189
+ $installedDeps[] = array($pChan, $pName, $pVer);
190
+
191
+
192
+ $title = isset($options['title']) ? $options['title'] : "Package installed: ";
193
+ $out = array($command => array('data'=>$installedDeps, 'assoc'=>$installedDepsAssoc, 'title'=>$title));
194
+
195
+ if($ftp) {
196
+ $packager->writeToRemoteCache($cache, $ftpObj);
197
+ @unlink($config->getFilename());
198
+ }
199
+
200
+ $this->ui()->output($out);
201
+ return $out[$command]['data'];
202
+ }
203
+
204
+ if(!$upgradeAllMode) {
205
+
206
+ if(count($params) < 2) {
207
+ throw new Exception("Argument should be: channelName packageName");
208
+ }
209
+ $channel = $params[0];
210
+ $package = $params[1];
211
+ $argVersionMax = isset($params[2]) ? $params[2]: false;
212
+ $argVersionMin = isset($params[3]) ? $params[3]: false;
213
+
214
+ $cache->checkChannel($channel, $config, $rest);
215
+ $channelName = $cache->chanName($channel);
216
+ $this->ui()->output("Checking dependencies of packages");
217
+ $packagesToInstall = $packager->getDependenciesList($channelName, $package, $cache, $config,
218
+ $argVersionMax, $argVersionMin, $withDepsMode, false, $rest
219
+ );
220
+ /*
221
+ * process 'failed' results
222
+ */
223
+ if(count($packagesToInstall['failed'])) {
224
+ $showError=!count($packagesToInstall['result']);
225
+ foreach($packagesToInstall['failed'] as $failed){
226
+ //$failed = array(
227
+ // 'name'=>$package,
228
+ // 'channel'=>$chanName,
229
+ // 'max'=>$versionMax,
230
+ // 'min'=>$versionMin,
231
+ // 'reason'=>$e->getMessage()
232
+ //);
233
+ $msg="Package {$failed['channel']}/{$failed['name']} failed: ".$failed['reason'];
234
+ if($showError){
235
+ $this->doError($command, $msg);
236
+ }else{
237
+ $this->ui()->output($msg);
238
+ }
239
+ }
240
+ }
241
+ $packagesToInstall = $packagesToInstall['result'];
242
+ } else {
243
+ if(empty($params[0])) {
244
+ $channels = $cache->getChannelNames();
245
+ } else {
246
+ $channel = $params[0];
247
+ if(!$cache->isChannel($channel)) {
248
+ throw new Exception("'{$channel}' is not existant channel name / valid uri");
249
+ }
250
+ $channels = $cache->chanName($channel);
251
+ }
252
+ $packagesToInstall = array();
253
+ $neededToUpgrade = $packager->getUpgradesList($channels, $cache, $config, $rest);
254
+ foreach($neededToUpgrade as $chan=>$packages) {
255
+ foreach($packages as $name=>$data) {
256
+ $versionTo = $data['to'];
257
+ $tmp = $packager->getDependenciesList($chan, $name, $cache, $config, $versionTo, $versionTo,
258
+ $withDepsMode, false, $rest
259
+ );
260
+ if(count($tmp['result'])) {
261
+ $packagesToInstall = array_merge($packagesToInstall, $tmp['result']);
262
+ }
263
+ }
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Make installation
269
+ */
270
+ $installedDeps = array();
271
+ $installedDepsAssoc = array();
272
+ $keys = array();
273
+
274
+ foreach($packagesToInstall as $package) {
275
+ try {
276
+ $pName = $package['name'];
277
+ $pChan = $package['channel'];
278
+ $pVer = $package['downloaded_version'];
279
+ $pInstallState = $package['install_state'];
280
+ $rest->setChannel($cache->chanUrl($pChan));
281
+
282
+ /**
283
+ * Skip existing packages
284
+ */
285
+ if ($upgradeMode && $cache->hasPackage($pChan, $pName, $pVer, $pVer)
286
+ || ('already_installed' == $pInstallState && !$forceMode)
287
+ ) {
288
+ $this->ui()->output("Already installed: {$pChan}/{$pName} {$pVer}, skipping");
289
+ continue;
290
+ }
291
+
292
+ if('incompartible' == $pInstallState) {
293
+ $this->ui()->output(
294
+ "Package incompartible with installed Magento: {$pChan}/{$pName} {$pVer}, skipping"
295
+ );
296
+ continue;
297
+ }
298
+
299
+ $conflicts = $cache->hasConflicts($pChan, $pName, $pVer);
300
+
301
+ if(false !== $conflicts) {
302
+ $conflicts = implode(", ",$conflicts);
303
+ if($forceMode) {
304
+ $this->doError($command, "Package {$pChan}/{$pName} {$pVer} conflicts with: ".$conflicts);
305
+ } else {
306
+ throw new Exception("Package {$pChan}/{$pName} {$pVer} conflicts with: ".$conflicts);
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Modifications
312
+ */
313
+ if (($upgradeMode || ($pInstallState == 'upgrade')) && !$ignoreModifiedMode) {
314
+ if($ftp) {
315
+ $modifications = $packager->getRemoteModifiedFiles($pChan, $pName, $cache, $config, $ftp);
316
+ } else {
317
+ $modifications = $packager->getLocalModifiedFiles($pChan, $pName, $cache, $config);
318
+ }
319
+ if (count($modifications) > 0) {
320
+ $this->ui()->output('Changed locally: ');
321
+ foreach ($modifications as $row) {
322
+ if(!$ftp) {
323
+ $this->ui()->output($config->magento_root.DS.$row);
324
+ } else {
325
+ $this->ui()->output($row);
326
+ }
327
+ }
328
+ /*$this->ui()->confirm('Do you want rewrite all files?');
329
+ continue;*/
330
+ }
331
+ }
332
+
333
+ if($ftp) {
334
+ $cwd=$ftpObj->getcwd();
335
+ $dir=$cwd . DIRECTORY_SEPARATOR .$config->downloader_path . DIRECTORY_SEPARATOR
336
+ . Mage_Connect_Config::DEFAULT_CACHE_PATH . DIRECTORY_SEPARATOR . trim( $pChan, "\\/");
337
+ $ftpObj->mkdirRecursive($dir,0777);
338
+ $ftpObj->chdir($cwd);
339
+ } else {
340
+ $dir = $config->getChannelCacheDir($pChan);
341
+ @mkdir($dir, 0777, true);
342
+ }
343
+ $dir = $config->getChannelCacheDir($pChan);
344
+ $packageFileName = $pName."-".$pVer.".tgz";
345
+ $file = $dir.DIRECTORY_SEPARATOR.$packageFileName;
346
+ if(!@file_exists($file)) {
347
+ $this->ui()->output("Starting to download $packageFileName ...");
348
+ $rest->downloadPackageFileOfRelease($pName, $pVer, $file);
349
+ $this->ui()->output(sprintf("...done: %s bytes", number_format(filesize($file))));
350
+ }
351
+
352
+ /**
353
+ * Remove old version package before install new
354
+ */
355
+ if ($cache->hasPackage($pChan, $pName)) {
356
+ if ($ftp) {
357
+ $packager->processUninstallPackageFtp($pChan, $pName, $cache, $ftpObj);
358
+ } else {
359
+ $packager->processUninstallPackage($pChan, $pName, $cache, $config);
360
+ }
361
+ $cache->deletePackage($pChan, $pName);
362
+ }
363
+
364
+ $package = new Mage_Connect_Package($file);
365
+ if ($clearInstallMode && $pInstallState != 'upgrade' && !$installAll) {
366
+ $this->validator()->validateContents($package->getContents(), $config);
367
+ $errors = $this->validator()->getErrors();
368
+ if (count($errors)) {
369
+ throw new Exception("Package '{$pName}' is invalid\n" . implode("\n", $errors));
370
+ }
371
+ }
372
+
373
+ $conflicts = $package->checkPhpDependencies();
374
+ if(true !== $conflicts) {
375
+ $confilcts = implode(",",$conflicts);
376
+ $err = "Package {$pChan}/{$pName} {$pVer} depends on PHP extensions: ".$conflicts;
377
+ if($forceMode) {
378
+ $this->doError($command, $err);
379
+ } else {
380
+ throw new Exception($err);
381
+ }
382
+ }
383
+
384
+ $conflicts = $package->checkPhpVersion();
385
+ if(true !== $conflicts) {
386
+ $err = "Package {$pChan}/{$pName} {$pVer}: ".$conflicts;
387
+ if($forceMode) {
388
+ $this->doError($command, $err);
389
+ } else {
390
+ throw new Exception($err);
391
+ }
392
+ }
393
+
394
+ /**
395
+ * @todo: make "Use custom permissions" functionality working
396
+ */
397
+ if(!$noFilesInstall) {
398
+ $this->ui()->output("Installing package {$pChan}/{$pName} {$pVer}");
399
+ if($ftp) {
400
+ $packager->processInstallPackageFtp($package, $file, $config, $ftpObj);
401
+ } else {
402
+ $packager->processInstallPackage($package, $file, $config);
403
+ }
404
+ $this->ui()->output("Package {$pChan}/{$pName} {$pVer} installed successfully");
405
+ }
406
+ $cache->addPackage($package);
407
+
408
+ $installedDepsAssoc[] = array('channel'=>$pChan, 'name'=>$pName, 'version'=>$pVer);
409
+ $installedDeps[] = array($pChan, $pName, $pVer);
410
+
411
+ } catch(Exception $e) {
412
+ $this->doError($command, $e->getMessage());
413
+ }
414
+ }
415
+
416
+
417
+
418
+ $title = isset($options['title']) ? $options['title'] : "Package installed: ";
419
+ $out = array($command => array('data'=>$installedDeps, 'assoc'=>$installedDepsAssoc, 'title'=>$title));
420
+
421
+ if($ftp) {
422
+ $packager->writeToRemoteCache($cache, $ftpObj);
423
+ @unlink($config->getFilename());
424
+ }
425
+
426
+ $this->ui()->output($out);
427
+ return $out[$command]['data'];
428
+
429
+ } catch (Exception $e) {
430
+ if($ftp) {
431
+ $packager->writeToRemoteCache($cache, $ftpObj);
432
+ @unlink($config->getFilename());
433
+ }
434
+ return $this->doError($command, $e->getMessage());
435
+ }
436
+ }
437
+
438
+ /**
439
+ * Upgrade action callback
440
+ * @param string $command
441
+ * @param array $options
442
+ * @param array $params
443
+ * @return void
444
+ */
445
+ public function doUpgrade($command, $options, $params)
446
+ {
447
+ $options['title'] = "Package upgraded: ";
448
+ return $this->doInstall($command, $options, $params);
449
+ }
450
+
451
+ /**
452
+ * Updgrade action callback
453
+ * @param string $command
454
+ * @param array $options
455
+ * @param array $params
456
+ * @return void
457
+ */
458
+ public function doUpgradeAll($command, $options, $params)
459
+ {
460
+ $options['title'] = "Package upgraded: ";
461
+ return $this->doInstall($command, $options, $params);
462
+ }
463
+
464
+ /**
465
+ * Uninstall package callback
466
+ * @param string $command
467
+ * @param array $options
468
+ * @param array $params
469
+ * @return unknown_type
470
+ */
471
+ public function doUninstall($command, $options, $params)
472
+ {
473
+ $this->cleanupParams($params);
474
+ //$this->splitPackageArgs($params);
475
+
476
+ try {
477
+ if(count($params) != 2) {
478
+ throw new Exception("Argument count should be = 2");
479
+ }
480
+
481
+ $channel = $params[0];
482
+ $package = $params[1];
483
+ $packager = $this->getPackager();
484
+ $withDepsMode = !isset($options['nodeps']);
485
+ $forceMode = isset($options['force']);
486
+
487
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
488
+ if($ftp) {
489
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
490
+ } else {
491
+ $cache = $this->getSconfig();
492
+ $config = $this->config();
493
+ }
494
+
495
+ $chan = $cache->getChannel($channel);
496
+ $channel = $cache->chanName($channel);
497
+ if(!$cache->hasPackage($channel, $package)) {
498
+ throw new Exception("Package is not installed");
499
+ }
500
+
501
+ $deletedPackages = array();
502
+ $list = $packager->getUninstallList($channel, $package, $cache, $config, $withDepsMode);
503
+ foreach($list['list'] as $packageData) {
504
+ try {
505
+ $reqd = $cache->requiredByOtherPackages(
506
+ $packageData['channel'],
507
+ $packageData['name'],
508
+ $list['list']
509
+ );
510
+ if(count($reqd)) {
511
+ $errMessage = "{$packageData['channel']}/{$packageData['name']} "
512
+ . "{$packageData['version']} is required by: ";
513
+ $t = array();
514
+ foreach($reqd as $r) {
515
+ $t[] = $r['channel']."/".$r['name']. " ".$r['version'];
516
+ }
517
+ $errMessage .= implode(", ", $t);
518
+ if($forceMode) {
519
+ $this->ui()->output("Warning: ".$errMessage);
520
+ } else {
521
+ throw new Exception($errMessage);
522
+ }
523
+ }
524
+ } catch(Exception $e) {
525
+ if($forceMode) {
526
+ $this->doError($command, $e->getMessage());
527
+ } else {
528
+ throw new Exception($e->getMessage());
529
+ }
530
+ }
531
+ }
532
+ foreach($list['list'] as $packageData) {
533
+ try {
534
+ list($chan, $pack) = array($packageData['channel'], $packageData['name']);
535
+ $packageName = $packageData['channel'] . "/" . $packageData['name'];
536
+ $this->ui()->output("Starting to uninstall $packageName ");
537
+ if($ftp) {
538
+ $packager->processUninstallPackageFtp($chan, $pack, $cache, $ftpObj);
539
+ } else {
540
+ $packager->processUninstallPackage($chan, $pack, $cache, $config);
541
+ }
542
+ $cache->deletePackage($chan, $pack);
543
+ $deletedPackages[] = array($chan, $pack);
544
+ $this->ui()->output("Package {$packageName} uninstalled");
545
+ } catch(Exception $e) {
546
+ if($forceMode) {
547
+ $this->doError($command, $e->getMessage());
548
+ } else {
549
+ throw new Exception($e->getMessage());
550
+ }
551
+ }
552
+ }
553
+ if($ftp) {
554
+ $packager->writeToRemoteCache($cache, $ftpObj);
555
+ @unlink($config->getFilename());
556
+ }
557
+ $out = array($command=>array('data'=>$deletedPackages, 'title'=>'Package deleted: '));
558
+ $this->ui()->output($out);
559
+
560
+ } catch (Exception $e) {
561
+ return $this->doError($command, $e->getMessage());
562
+ }
563
+
564
+ }
565
+
566
+ }
567
+
downloader/lib/Mage/Connect/Command/Install_Header.php ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ $commands = array(
28
+
29
+ 'install-file' => array(
30
+ 'summary' => 'Install Package Archive File',
31
+ 'function' => 'doInstall',
32
+ 'shortcut' => 'if',
33
+ 'options' => array(),
34
+ 'doc' => '',
35
+ ),
36
+ 'install' => array(
37
+ 'summary' => 'Install Package',
38
+ 'function' => 'doInstall',
39
+ 'shortcut' => 'i',
40
+ 'options' => array(
41
+ 'force' => array(
42
+ 'shortopt' => 'f',
43
+ 'doc' => 'will overwrite newer installed packages',
44
+ ),
45
+ 'loose' => array(
46
+ 'shortopt' => 'l',
47
+ 'doc' => 'do not check for recommended dependency version',
48
+ ),
49
+ 'nodeps' => array(
50
+ 'shortopt' => 'n',
51
+ 'doc' => 'ignore dependencies, install anyway',
52
+ ),
53
+ 'ignore-errors' => array(
54
+ 'doc' => 'force install even if there were errors',
55
+ ),
56
+ 'alldeps' => array(
57
+ 'shortopt' => 'a',
58
+ 'doc' => 'install all required and optional dependencies',
59
+ ),
60
+ 'pretend' => array(
61
+ 'shortopt' => 'p',
62
+ 'doc' => 'Only list the packages that would be downloaded',
63
+ ),
64
+ 'ftp=' => array(
65
+ 'shortopt' => 'r=',
66
+ 'doc' => 'Remote side FTP connect string',
67
+ ),
68
+ ),
69
+ 'doc' => '[channel/]<package> ...
70
+ Installs one or more PEAR packages. You can specify a package to
71
+ install in four ways:
72
+
73
+ "Package-1.0.tgz" : installs from a local file
74
+
75
+ "http://example.com/Package-1.0.tgz" : installs from
76
+ anywhere on the net.
77
+
78
+ "package.xml" : installs the package described in
79
+ package.xml. Useful for testing, or for wrapping a PEAR package in
80
+ another package manager such as RPM.
81
+
82
+ "Package[-version/state][.tar]" : queries your default channel\'s server
83
+ ({config master_server}) and downloads the newest package with
84
+ the preferred quality/state ({config preferred_state}).
85
+
86
+ To retrieve Package version 1.1, use "Package-1.1," to retrieve
87
+ Package state beta, use "Package-beta." To retrieve an uncompressed
88
+ file, append .tar (make sure there is no file by the same name first)
89
+
90
+ To download a package from another channel, prefix with the channel name like
91
+ "channel/Package"
92
+
93
+ More than one package may be specified at once. It is ok to mix these
94
+ four ways of specifying packages.
95
+ '),
96
+ 'upgrade' => array(
97
+ 'summary' => 'Upgrade Package',
98
+ 'function' => 'doUpgrade',
99
+ 'shortcut' => 'up',
100
+ 'options' => array(
101
+ 'channel' => array(
102
+ 'shortopt' => 'c',
103
+ 'doc' => 'upgrade packages from a specific channel',
104
+ 'arg' => 'CHAN',
105
+ ),
106
+ 'force' => array(
107
+ 'shortopt' => 'f',
108
+ 'doc' => 'overwrite newer installed packages',
109
+ ),
110
+ 'loose' => array(
111
+ 'shortopt' => 'l',
112
+ 'doc' => 'do not check for recommended dependency version',
113
+ ),
114
+ 'nodeps' => array(
115
+ 'shortopt' => 'n',
116
+ 'doc' => 'ignore dependencies, upgrade anyway',
117
+ ),
118
+ 'register-only' => array(
119
+ 'shortopt' => 'r',
120
+ 'doc' => 'do not install files, only register the package as upgraded',
121
+ ),
122
+ 'nobuild' => array(
123
+ 'shortopt' => 'B',
124
+ 'doc' => 'don\'t build C extensions',
125
+ ),
126
+ 'nocompress' => array(
127
+ 'shortopt' => 'Z',
128
+ 'doc' => 'request uncompressed files when downloading',
129
+ ),
130
+ 'installroot' => array(
131
+ 'shortopt' => 'R',
132
+ 'arg' => 'DIR',
133
+ 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
134
+ ),
135
+ 'ignore-errors' => array(
136
+ 'doc' => 'force install even if there were errors',
137
+ ),
138
+ 'alldeps' => array(
139
+ 'shortopt' => 'a',
140
+ 'doc' => 'install all required and optional dependencies',
141
+ ),
142
+ 'onlyreqdeps' => array(
143
+ 'shortopt' => 'o',
144
+ 'doc' => 'install all required dependencies',
145
+ ),
146
+ 'offline' => array(
147
+ 'shortopt' => 'O',
148
+ 'doc' => 'do not attempt to download any urls or contact channels',
149
+ ),
150
+ 'pretend' => array(
151
+ 'shortopt' => 'p',
152
+ 'doc' => 'Only list the packages that would be downloaded',
153
+ ),
154
+ ),
155
+ 'doc' => '<package> ...
156
+ Upgrades one or more PEAR packages. See documentation for the
157
+ "install" command for ways to specify a package.
158
+
159
+ When upgrading, your package will be updated if the provided new
160
+ package has a higher version number (use the -f option if you need to
161
+ upgrade anyway).
162
+
163
+ More than one package may be specified at once.
164
+ '),
165
+ 'upgrade-all' => array(
166
+ 'summary' => 'Upgrade All Packages',
167
+ 'function' => 'doUpgradeAll',
168
+ 'shortcut' => 'ua',
169
+ 'options' => array(
170
+ 'channel' => array(
171
+ 'shortopt' => 'c',
172
+ 'doc' => 'upgrade packages from a specific channel',
173
+ 'arg' => 'CHAN',
174
+ ),
175
+ 'nodeps' => array(
176
+ 'shortopt' => 'n',
177
+ 'doc' => 'ignore dependencies, upgrade anyway',
178
+ ),
179
+ 'register-only' => array(
180
+ 'shortopt' => 'r',
181
+ 'doc' => 'do not install files, only register the package as upgraded',
182
+ ),
183
+ 'nobuild' => array(
184
+ 'shortopt' => 'B',
185
+ 'doc' => 'don\'t build C extensions',
186
+ ),
187
+ 'nocompress' => array(
188
+ 'shortopt' => 'Z',
189
+ 'doc' => 'request uncompressed files when downloading',
190
+ ),
191
+ 'installroot' => array(
192
+ 'shortopt' => 'R',
193
+ 'arg' => 'DIR',
194
+ 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
195
+ ),
196
+ 'ignore-errors' => array(
197
+ 'doc' => 'force install even if there were errors',
198
+ ),
199
+ 'loose' => array(
200
+ 'doc' => 'do not check for recommended dependency version',
201
+ ),
202
+ ),
203
+ 'doc' => '
204
+ WARNING: This function is deprecated in favor of using the upgrade command with no params
205
+
206
+ Upgrades all packages that have a newer release available. Upgrades are
207
+ done only if there is a release available of the state specified in
208
+ "preferred_state" (currently {config preferred_state}), or a state considered
209
+ more stable.
210
+ '),
211
+ 'uninstall' => array(
212
+ 'summary' => 'Un-install Package',
213
+ 'function' => 'doUninstall',
214
+ 'shortcut' => 'un',
215
+ 'options' => array(
216
+ 'nodeps' => array(
217
+ 'shortopt' => 'n',
218
+ 'doc' => 'ignore dependencies, uninstall anyway',
219
+ ),
220
+ 'register-only' => array(
221
+ 'shortopt' => 'r',
222
+ 'doc' => 'do not remove files, only register the packages as not installed',
223
+ ),
224
+ 'ignore-errors' => array(
225
+ 'doc' => 'force install even if there were errors',
226
+ ),
227
+ 'offline' => array(
228
+ 'shortopt' => 'O',
229
+ 'doc' => 'do not attempt to uninstall remotely',
230
+ ),
231
+ ),
232
+ 'doc' => '[channel/]<package> ...
233
+ Uninstalls one or more PEAR packages. More than one package may be
234
+ specified at once. Prefix with channel name to uninstall from a
235
+ channel not in your default channel ({config default_channel})
236
+ '),
237
+ );
downloader/lib/Mage/Connect/Command/Package.php ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ final class Mage_Connect_Command_Package
28
+ extends Mage_Connect_Command
29
+ {
30
+ /**
31
+ * Dependencies list
32
+ * @var array
33
+ */
34
+ private $_depsList = array();
35
+
36
+ /**
37
+ * Releases list
38
+ * @var array
39
+ */
40
+ private $_releasesList = array();
41
+
42
+ /**
43
+ * Package command callback
44
+ * @param string $command
45
+ * @param array $options
46
+ * @param array $params
47
+ * @return void
48
+ */
49
+ public function doPackage($command, $options, $params)
50
+ {
51
+ $this->cleanupParams($params);
52
+
53
+ if(count($params) < 1) {
54
+ return $this->doError($command, "Parameters count should be >= 1");
55
+ }
56
+
57
+ $file = strtolower($params[0]);
58
+ $file = realpath($file);
59
+
60
+ if(!file_exists($file)) {
61
+ return $this->doError($command, "File {$params[0]} doesn't exist");
62
+ }
63
+
64
+ try {
65
+ $packager = new Mage_Connect_Package($file);
66
+ $res = $packager->validate();
67
+ if(!$res) {
68
+ $this->doError($command, implode("\n", $packager->getErrors()));
69
+ return;
70
+ }
71
+ $packager->save(dirname($file));
72
+ $this->ui()->output('Done building package');
73
+ } catch (Exception $e) {
74
+ $this->doError( $command, $e->getMessage() );
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Display/get installation information for package
80
+ * @param string $command
81
+ * @param array $options
82
+ * @param array $params
83
+ * @return void/array
84
+ */
85
+ public function doPackagePrepare($command, $options, $params)
86
+ {
87
+ $this->cleanupParams($params);
88
+ $channelAuth = array();
89
+ if (isset($options['auth'])) {
90
+ $channelAuth = $options['auth'];
91
+ $options['auth'] = null;
92
+ }
93
+ try {
94
+
95
+ if(count($params) < 2) {
96
+ return $this->doError($command, "Argument count should be >= 2");
97
+ }
98
+
99
+ $channel = $params[0];
100
+ $package = $params[1];
101
+
102
+ $argVersionMin = isset($params[3]) ? $params[3] : false;
103
+ $argVersionMax = isset($params[2]) ? $params[2] : false;
104
+
105
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
106
+ $packager = $this->getPackager();
107
+ if ($ftp) {
108
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
109
+ } else {
110
+ $cache = $this->getSconfig();
111
+ $config = $this->config();
112
+ }
113
+
114
+ $rest = new Mage_Connect_Rest($config->protocol);
115
+ if(!empty($channelAuth)){
116
+ $rest->getLoader()->setCredentials($channelAuth['username'], $channelAuth['password']);
117
+ }
118
+
119
+ $cache->checkChannel($channel, $config, $rest);
120
+
121
+ $data = $packager->getDependenciesList($channel, $package, $cache, $config,
122
+ $argVersionMax, $argVersionMin, true, false, $rest
123
+ );
124
+
125
+ $result = array();
126
+ foreach ($data['result'] as $_package) {
127
+ $_result['channel'] = $_package['channel'];
128
+ $_result['name'] = $_package['name'];
129
+ $_result['version'] = $_package['downloaded_version'];
130
+ $_result['stability'] = $_package['stability'];
131
+ $_result['install_state'] = $_package['install_state'];
132
+ $_result['message'] = $_package['message'];
133
+ $result[] = $_result;
134
+ }
135
+ if (!count($data['result']) && isset($data['failed']) && !empty($data['failed'])) {
136
+ foreach ($data['failed'] as $_package) {
137
+ $reason = $_package['channel'] . '/' . $_package['name'] . ': ' . $_package['reason'];
138
+ $this->doError($command, $reason);
139
+ }
140
+ }
141
+
142
+ $this->ui()->output(array($command=> array('data'=>$result, 'title'=>"Package installation information for {$params[1]}: ")));
143
+
144
+ } catch (Exception $e) {
145
+ $this->doError($command, $e->getMessage());
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Display/get dependencies
151
+ * @param string $command
152
+ * @param array $options
153
+ * @param array $params
154
+ * @return void/array
155
+ */
156
+ public function doPackageDependencies($command, $options, $params)
157
+ {
158
+ $this->cleanupParams($params);
159
+ try {
160
+ if(count($params) < 2) {
161
+ return $this->doError($command, "Argument count should be >= 2");
162
+ }
163
+
164
+ $channel = $params[0];
165
+ $package = $params[1];
166
+
167
+ $argVersionMin = isset($params[3]) ? $params[3] : false;
168
+ $argVersionMax = isset($params[2]) ? $params[2] : false;
169
+
170
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
171
+ $packager = $this->getPackager();
172
+ if($ftp) {
173
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
174
+ } else {
175
+ $cache = $this->getSconfig();
176
+ $config = $this->config();
177
+ }
178
+ $data = $packager->getDependenciesList($channel, $package, $cache, $config, $argVersionMax, $argVersionMin);
179
+ $this->ui()->output(array($command=> array('data'=>$data['deps'], 'title'=>"Package deps for {$params[1]}: ")));
180
+
181
+ } catch (Exception $e) {
182
+ $this->doError($command, $e->getMessage());
183
+ }
184
+ }
185
+
186
+ public function doConvert($command, $options, $params)
187
+ {
188
+ $this->cleanupParams($params);
189
+ try {
190
+ if(count($params) < 1) {
191
+ throw new Exception("Arguments should be: source.tgz [target.tgz]");
192
+ }
193
+ $sourceFile = $params[0];
194
+ $converter = new Mage_Connect_Converter();
195
+ $targetFile = isset($params[1]) ? $params[1] : false;
196
+ $result = $converter->convertPearToMage($sourceFile, $targetFile);
197
+ $this->ui()->output("Saved to: ".$result);
198
+ } catch (Exception $e) {
199
+ $this->doError($command, $e->getMessage());
200
+ }
201
+
202
+ }
203
+
204
+ }
downloader/lib/Mage/Connect/Command/Package_Header.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ $commands = array(
28
+ 'package' => array(
29
+ 'summary' => 'Build Package',
30
+ 'function' => 'doPackage',
31
+ 'shortcut' => 'p',
32
+ 'options' => array(
33
+ 'nocompress' => array(
34
+ 'shortopt' => 'Z',
35
+ 'doc' => 'Do not gzip the package file'
36
+ ),
37
+ 'showname' => array(
38
+ 'shortopt' => 'n',
39
+ 'doc' => 'Print the name of the packaged file.',
40
+ ),
41
+ ),
42
+ 'doc' => '[descfile] [descfile2]
43
+ Creates a PEAR package from its description file (usually called
44
+ package.xml). If a second packagefile is passed in, then
45
+ the packager will check to make sure that one is a package.xml
46
+ version 1.0, and the other is a package.xml version 2.0. The
47
+ package.xml version 1.0 will be saved as "package.xml" in the archive,
48
+ and the other as "package2.xml" in the archive"
49
+ '
50
+ ),
51
+ 'package-dependencies' => array(
52
+ 'summary' => 'Show package dependencies',
53
+ 'function' => 'doPackageDependencies',
54
+ 'shortcut' => 'pd',
55
+ 'options' => array(),
56
+ 'doc' => '<package-file> or <package.xml> or <install-package-name>
57
+ List all dependencies the package has.
58
+ Can take a tgz / tar file, package.xml or a package name of an installed package.'
59
+ ),
60
+ 'package-prepare' => array(
61
+ 'summary' => 'Show installation information of package',
62
+ 'function' => 'doPackagePrepare',
63
+ 'shortcut' => 'pp',
64
+ 'options' => array(),
65
+ 'doc' => '<package-file> or <package.xml> or <install-package-name>
66
+ List all dependencies the package has.
67
+ Can take a tgz / tar file, package.xml or a package name of an installed package.'
68
+ ),
69
+ 'convert' => array(
70
+ 'summary' => 'Convert old magento PEAR package to new format',
71
+ 'function' => 'doConvert',
72
+ 'shortcut' => 'conv',
73
+ 'options' => array(),
74
+ 'doc' => ''
75
+ ),
76
+ );
downloader/lib/Mage/Connect/Command/Registry.php ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ final class Mage_Connect_Command_Registry
28
+ extends Mage_Connect_Command
29
+ {
30
+ const PACKAGE_PEAR_DIR = 'pearlib/php/.registry';
31
+
32
+ /**
33
+ * List-installed callback
34
+ * @param string $command
35
+ * @param array $options
36
+ * @param array $params
37
+ * @return void
38
+ */
39
+ public function doList($command, $options, $params)
40
+ {
41
+ $this->cleanupParams($params);
42
+ try {
43
+ $packager = $this->getPackager();
44
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
45
+ if($ftp) {
46
+ list($cache, $ftpObj) = $packager->getRemoteCache($ftp);
47
+ } else {
48
+ $cache = $this->getSconfig();
49
+ }
50
+ if(!empty($params[0])) {
51
+ $chanName = $conf->chanName($params[0]);
52
+ $data = $cache->getInstalledPackages($chanName);
53
+ } else {
54
+ $data = $cache->getInstalledPackages();
55
+ }
56
+ if($ftp) {
57
+ @unlink($cache->getFilename());
58
+ }
59
+ $this->ui()->output(array($command=>array('data'=>$data, 'channel-title'=>"Installed package for channel '%s' :")));
60
+ } catch (Exception $e) {
61
+ if($ftp) {
62
+ @unlink($cache->getFilename());
63
+ }
64
+ $this->doError($command, $e->getMessage());
65
+ }
66
+
67
+ }
68
+
69
+ /**
70
+ * list-files callback
71
+ * @param string $command
72
+ * @param array $options
73
+ * @param array $params
74
+ * @return void
75
+ */
76
+ public function doFileList($command, $options, $params)
77
+ {
78
+ $this->cleanupParams($params);
79
+ //$this->splitPackageArgs($params);
80
+ try {
81
+ $channel = false;
82
+ if(count($params) < 2) {
83
+ throw new Exception("Argument count should be = 2");
84
+ }
85
+ $channel = $params[0];
86
+ $package = $params[1];
87
+
88
+ $packager = $this->getPackager();
89
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
90
+ if($ftp) {
91
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
92
+ } else {
93
+ $cache = $this->getSconfig();
94
+ $confif = $this->config();
95
+ }
96
+ if(!$cache->hasPackage($channel, $package)) {
97
+ return $this->ui()->output("No package found: {$channel}/{$package}");
98
+ }
99
+
100
+ $p = $cache->getPackageObject($channel, $package);
101
+ $contents = $p->getContents();
102
+ if($ftp) {
103
+ $ftpObj->close();
104
+ }
105
+ if(!count($contents)) {
106
+ return $this->ui()->output("No contents for package {$package}");
107
+ }
108
+ $title = ("Contents of '{$package}': ");
109
+ if($ftp) {
110
+ @unlink($config->getFilename());
111
+ @unlink($cache->getFilename());
112
+ }
113
+
114
+ $this->ui()->output(array($command=>array('data'=>$contents, 'title'=>$title)));
115
+
116
+ } catch (Exception $e) {
117
+ if($ftp) {
118
+ @unlink($config->getFilename());
119
+ @unlink($cache->getFilename());
120
+ }
121
+ $this->doError($command, $e->getMessage());
122
+ }
123
+
124
+ }
125
+
126
+ /**
127
+ * Installed package info
128
+ * info command callback
129
+ * @param string $command
130
+ * @param array $options
131
+ * @param array $params
132
+ * @return
133
+ */
134
+ public function doInfo($command, $options, $params)
135
+ {
136
+ $this->cleanupParams($params);
137
+ //$this->splitPackageArgs($params);
138
+
139
+ $cache = null;
140
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
141
+ try {
142
+ $channel = false;
143
+ if(count($params) < 2) {
144
+ throw new Exception("Argument count should be = 2");
145
+ }
146
+ $channel = $params[0];
147
+ $package = $params[1];
148
+ $packager = $this->getPackager();
149
+ if($ftp) {
150
+ list($cache, $ftpObj) = $packager->getRemoteCache($ftp);
151
+ } else {
152
+ $cache = $this->getSconfig();
153
+ }
154
+
155
+ if(!$cache->isChannel($channel)) {
156
+ throw new Exception("'{$channel}' is not a valid installed channel name/uri");
157
+ }
158
+ $channelUri = $cache->chanUrl($channel);
159
+ $rest = $this->rest();
160
+ $rest->setChannel($channelUri);
161
+ $releases = $rest->getReleases($package);
162
+ if(false === $releases) {
163
+ throw new Exception("No information found about {$channel}/{$package}");
164
+ }
165
+ $data = array($command => array('releases'=>$releases));
166
+ if($ftp) {
167
+ @unlink($cache->getFilename());
168
+ }
169
+ $this->ui()->output($data);
170
+ } catch (Exception $e) {
171
+ if ($ftp && isset($cache)) {
172
+ @unlink($cache->getFilename());
173
+ }
174
+ $this->doError($command, $e->getMessage());
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Synchronize manually installed package info with local cache
180
+ *
181
+ * @param string $command
182
+ * @param array $options
183
+ * @param array $params
184
+ */
185
+ public function doSync($command, $options, $params)
186
+ {
187
+ $this->cleanupParams($params);
188
+ try {
189
+ $packager = $this->getPackager();
190
+ $cache = null;
191
+ $config = null;
192
+ $ftpObj = null;
193
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
194
+ if($ftp) {
195
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
196
+ } else {
197
+ $config = $this->config();
198
+ $cache = $this->getSconfig();
199
+ }
200
+ if ($this->_checkPearData($config)) {
201
+ $this->doSyncPear($command, $options, $params);
202
+ }
203
+
204
+ $packageDir = $config->magento_root . DS . Mage_Connect_Package::PACKAGE_XML_DIR;
205
+ if (is_dir($packageDir)) {
206
+ $entries = scandir($packageDir);
207
+ foreach ((array)$entries as $entry) {
208
+ $path = $packageDir. DS .$entry;
209
+ $info = pathinfo($path);
210
+ if ($entry == '.' || $entry == '..' || is_dir($path) || $info['extension'] != 'xml') {
211
+ continue;
212
+ }
213
+
214
+ if (is_readable($path)) {
215
+ $data = file_get_contents($path);
216
+ if ($data === false) {
217
+ continue;
218
+ }
219
+
220
+ $package = new Mage_Connect_Package($data);
221
+ $name = $package->getName();
222
+ $channel = $package->getChannel();
223
+ $version = $package->getVersion();
224
+ if (!$cache->isChannel($channel) && $channel == $config->root_channel) {
225
+ $cache->addChannel($channel, $config->root_channel_uri);
226
+ }
227
+ if (!$cache->hasPackage($channel, $name, $version, $version)) {
228
+ $cache->addPackage($package);
229
+ $this->ui()->output("Successfully added: {$channel}/{$name}-{$version}");
230
+ }
231
+ }
232
+ }
233
+ if ($ftp) {
234
+ $packager->writeToRemoteCache($cache, $ftpObj);
235
+ }
236
+ }
237
+ } catch (Exception $e) {
238
+ $this->doError($command, $e->getMessage());
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Synchronize packages installed earlier (by pear installer) with local cache
244
+ *
245
+ * @param string $command
246
+ * @param array $options
247
+ * @param array $params
248
+ */
249
+ public function doSyncPear($command, $options, $params)
250
+ {
251
+ $this->cleanupParams($params);
252
+ try {
253
+ $packager = $this->getPackager();
254
+ $cache = null;
255
+ $config = null;
256
+ $ftpObj = null;
257
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
258
+ if($ftp) {
259
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
260
+ } else {
261
+ $config = $this->config();
262
+ $cache = $this->getSconfig();
263
+ }
264
+
265
+ $pkglist = array();
266
+ if (!$this->_checkPearData($config)) {
267
+ return $pkglist;
268
+ }
269
+
270
+ $pearStorage = $config->magento_root . DS . $config->downloader_path . DS . self::PACKAGE_PEAR_DIR;
271
+ $channels = array(
272
+ '.channel.connect.magentocommerce.com_community',
273
+ '.channel.connect.magentocommerce.com_core'
274
+ );
275
+ foreach ($channels as $channel) {
276
+ $channelDirectory = $pearStorage . DS . $channel;
277
+ if (!file_exists($channelDirectory) || !is_dir($channelDirectory)) {
278
+ continue;
279
+ }
280
+
281
+ $dp = opendir($channelDirectory);
282
+ if (!$dp) {
283
+ continue;
284
+ }
285
+
286
+ while ($ent = readdir($dp)) {
287
+ if ($ent{0} == '.' || substr($ent, -4) != '.reg') {
288
+ continue;
289
+ }
290
+ $pkglist[] = array('file'=>$ent, 'channel'=>$channel);
291
+ }
292
+ closedir($dp);
293
+ }
294
+
295
+ $package = new Mage_Connect_Package();
296
+ foreach ($pkglist as $pkg) {
297
+ $pkgFilename = $pearStorage . DS . $pkg['channel'] . DS . $pkg['file'];
298
+ if (!file_exists($pkgFilename)) {
299
+ continue;
300
+ }
301
+ $data = file_get_contents($pkgFilename);
302
+ $data = unserialize($data);
303
+
304
+ $package->importDataV1x($data);
305
+ $name = $package->getName();
306
+ $channel = $package->getChannel();
307
+ $version = $package->getVersion();
308
+ if (!$cache->isChannel($channel) && $channel == $config->root_channel) {
309
+ $cache->addChannel($channel, $config->root_channel_uri);
310
+ }
311
+ if (!$cache->hasPackage($channel, $name, $version, $version)) {
312
+ $cache->addPackage($package);
313
+
314
+ if($ftp) {
315
+ $localXml = tempnam(sys_get_temp_dir(),'package');
316
+ @file_put_contents($localXml, $package->getPackageXml());
317
+
318
+ if (is_file($localXml)) {
319
+ $ftpDir = $ftpObj->getcwd();
320
+ $remoteXmlPath = $ftpDir . '/' . Mage_Connect_Package::PACKAGE_XML_DIR;
321
+ $remoteXml = $package->getReleaseFilename() . '.xml';
322
+ $ftpObj->mkdirRecursive($remoteXmlPath);
323
+ $ftpObj->upload($remoteXml, $localXml, 0777, 0666);
324
+ $ftpObj->chdir($ftpDir);
325
+ }
326
+ } else {
327
+ $destDir = rtrim($config->magento_root, "\\/") . DS . Mage_Connect_Package::PACKAGE_XML_DIR;
328
+ $destFile = $package->getReleaseFilename() . '.xml';
329
+ $dest = $destDir . DS . $destFile;
330
+
331
+ @mkdir($destDir, 0777, true);
332
+ @file_put_contents($dest, $package->getPackageXml());
333
+ @chmod($dest, 0666);
334
+ }
335
+
336
+ $this->ui()->output("Successfully added: {$channel}/{$name}-{$version}");
337
+ }
338
+
339
+ }
340
+
341
+ $config->sync_pear = true;
342
+ if($ftp) {
343
+ $packager->writeToRemoteCache($cache, $ftpObj);
344
+ @unlink($config->getFilename());
345
+ }
346
+ } catch (Exception $e) {
347
+ $this->doError($command, $e->getMessage());
348
+ }
349
+
350
+ return true;
351
+ }
352
+
353
+ /**
354
+ * Check is need to sync old pear data
355
+ *
356
+ * @param Mage_Connect_Config $config
357
+ * @return boolean
358
+ */
359
+ protected function _checkPearData($config) {
360
+ $pearStorage = $config->magento_root . DS . $config->downloader_path . DS . self::PACKAGE_PEAR_DIR;
361
+ return (!$config->sync_pear) && file_exists($pearStorage) && is_dir($pearStorage);
362
+ }
363
+
364
+ }
downloader/lib/Mage/Connect/Command/Registry_Header.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ $commands = array(
28
+ 'list-installed' => array(
29
+ 'summary' => 'List Installed Packages In The Default Channel',
30
+ 'function' => 'doList',
31
+ 'shortcut' => 'l',
32
+ 'options' => array(
33
+ 'channel' => array(
34
+ 'shortopt' => 'c',
35
+ 'doc' => 'list installed packages from this channel',
36
+ 'arg' => 'CHAN',
37
+ ),
38
+ 'allchannels' => array(
39
+ 'shortopt' => 'a',
40
+ 'doc' => 'list installed packages from all channels',
41
+ ),
42
+ ),
43
+ 'doc' => '<package>
44
+ If invoked without parameters, this command lists the PEAR packages
45
+ installed in your php_dir ({config php_dir}). With a parameter, it
46
+ lists the files in a package.
47
+ ',
48
+ ),
49
+ 'list-files' => array(
50
+ 'summary' => 'List Files In Installed Package',
51
+ 'function' => 'doFileList',
52
+ 'shortcut' => 'fl',
53
+ 'options' => array(),
54
+ 'doc' => '<package>
55
+ List the files in an installed package.
56
+ '
57
+ ),
58
+ 'info' => array(
59
+ 'summary' => 'Display information about a package',
60
+ 'function' => 'doInfo',
61
+ 'shortcut' => 'in',
62
+ 'options' => array(),
63
+ 'doc' => '<package>
64
+ Displays information about a package. The package argument may be a
65
+ local package file, an URL to a package file, or the name of an
66
+ installed package.'
67
+ ),
68
+ 'sync' => array(
69
+ 'summary' => 'Synchronize Manually Installed Packages',
70
+ 'function' => 'doSync',
71
+ 'shortcut' => 'snc',
72
+ 'options' => array(),
73
+ 'doc' => '<package>
74
+ Synchronize manually installed package info with local cache.'
75
+ ),
76
+ 'sync-pear' => array(
77
+ 'summary' => 'Synchronize already Installed Packages by pear',
78
+ 'function' => 'doSyncPear',
79
+ 'shortcut' => 'sncp',
80
+ 'options' => array(),
81
+ 'doc' => '<package>
82
+ Synchronize already Installed Packages by pear.'
83
+ )
84
+ );
downloader/lib/Mage/Connect/Command/Remote.php ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ final class Mage_Connect_Command_Remote
28
+ extends Mage_Connect_Command
29
+ {
30
+
31
+ /**
32
+ * List-upgrades callback
33
+ * @param srting $command
34
+ * @param array $options
35
+ * @param array $params
36
+ * @return void
37
+ */
38
+ public function doListUpgrades($command, $options, $params)
39
+ {
40
+
41
+ $this->cleanupParams($params);
42
+ try {
43
+ $packager = new Mage_Connect_Packager();
44
+ $channelAuth = isset($options['auth'])?$options['auth']:array();
45
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
46
+ if($ftp) {
47
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
48
+ } else {
49
+ $cache = $this->getSconfig();
50
+ $config = $this->config();
51
+ }
52
+
53
+ if(!empty($params[0])) {
54
+ $channels = $params[0];
55
+ $cache->getChannel($channels);
56
+ } else {
57
+ $channels = $cache->getChannelNames();
58
+ }
59
+ $rest = $this->rest();
60
+ if(!empty($channelAuth)){
61
+ $rest->getLoader()->setCredentials($channelAuth['username'], $channelAuth['password']);
62
+ }
63
+ $ups = $packager->getUpgradesList($channels, $cache, $config, $rest);
64
+
65
+ if(count($ups)) {
66
+ $data = array($command => array('data'=>$ups));
67
+ } else {
68
+ $data = "No upgrades available";
69
+ }
70
+ $this->ui()->output($data);
71
+ } catch(Exception $e) {
72
+ $this->doError($command, $e->getMessage());
73
+ }
74
+ }
75
+
76
+
77
+ /**
78
+ * List available
79
+ * @param $command
80
+ * @param $options
81
+ * @param $params
82
+ * @return unknown_type
83
+ */
84
+
85
+ public function doListAvailable($command, $options, $params)
86
+ {
87
+ $this->cleanupParams($params);
88
+
89
+ try {
90
+ $packager = new Mage_Connect_Packager();
91
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
92
+ if($ftp) {
93
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
94
+ } else {
95
+ $cache = $this->getSconfig();
96
+ $config = $this->config();
97
+ }
98
+
99
+ if(!empty($params[0])) {
100
+ $channels = array($params[0]);
101
+ $cache->getChannel($channels[0]);
102
+ } else {
103
+ $channels = $cache->getChannelNames();
104
+ }
105
+
106
+
107
+
108
+ $packs = array();
109
+ foreach ($channels as $channel) {
110
+ try {
111
+ $chan = $cache->getChannel($channel);
112
+ $uri = $cache->chanUrl($channel);
113
+
114
+ $rest = $this->rest();
115
+ $rest->setChannel($uri);
116
+
117
+ $packages = $rest->getPackages();
118
+ if(!count($packages)) {
119
+ $this->ui()->output("Channel '{$channel}' has no packages");
120
+ continue;
121
+ }
122
+ $packs[$channel]['title'] = "Packages for channel '".$channel."':";
123
+ foreach($packages as $p) {
124
+ $packageName = $p['n'];
125
+ $releases = array();
126
+ foreach($p['r'] as $k=>$r) {
127
+ $releases[$r] = $rest->shortStateToLong($k);
128
+ }
129
+ $packs[$channel]['packages'][$packageName]['releases'] = $releases;
130
+ }
131
+ } catch (Exception $e) {
132
+ $this->doError($command, $e->getMessage());
133
+ }
134
+ }
135
+ $dataOut = array();
136
+ $dataOut[$command]= array('data'=>$packs);
137
+ $this->ui()->output($dataOut);
138
+
139
+ } catch(Exception $e) {
140
+ $this->doError($command, $e->getMessage());
141
+ }
142
+
143
+ }
144
+
145
+ /**
146
+ * Download command callback
147
+ *
148
+ * @param string $command
149
+ * @param array $options
150
+ * @param array $params
151
+ * @return void
152
+ */
153
+ public function doDownload($command, $options, $params)
154
+ {
155
+ $this->cleanupParams($params);
156
+ //$this->splitPackageArgs($params);
157
+ try {
158
+ if(count($params) < 2) {
159
+ throw new Exception("Arguments should be: channel Package");
160
+ }
161
+
162
+ $channel = $params[0];
163
+ $package = $params[1];
164
+
165
+ $packager = $this->getPackager();
166
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
167
+ if($ftp) {
168
+ list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp);
169
+ } else {
170
+ $cache = $this->getSconfig();
171
+ $config = $this->config();
172
+ }
173
+
174
+ $chan = $cache->getChannel($channel);
175
+ $uri = $cache->chanUrl($channel);
176
+
177
+ $rest = $this->rest();
178
+ $rest->setChannel($uri);
179
+ $c = $rest->getReleases($package);
180
+ if(!count($c)) {
181
+ throw new Exception("No releases found for package");
182
+ }
183
+ $version = $cache->detectVersionFromRestArray($c);
184
+ $dir = $config->getChannelCacheDir($channel);
185
+ $file = $dir.DIRECTORY_SEPARATOR.$package."-".$version.".tgz";
186
+ $rest->downloadPackageFileOfRelease($package, $version, $file);
187
+ if($ftp) {
188
+ @unlink($config->getFilename());
189
+ @unlink($cache->getFilename());
190
+ }
191
+ $this->ui()->output("Saved to: ". $file);
192
+ } catch (Exception $e) {
193
+ if($ftp) {
194
+ @unlink($config->getFilename());
195
+ @unlink($cache->getFilename());
196
+ }
197
+ $this->doError($command, $e->getMessage());
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Clear cache command callback
203
+ * @param string $command
204
+ * @param array $options
205
+ * @param array $params
206
+ * @return void
207
+ */
208
+ public function doClearCache($command, $options, $params)
209
+ {
210
+ $this->cleanupParams($params);
211
+ try {
212
+ $packager = new Mage_Connect_Packager();
213
+ $ftp = empty($options['ftp']) ? false : $options['ftp'];
214
+ if($ftp) {
215
+ list($cache, $ftpObj) = $packager->getRemoteCache($ftp);
216
+ $cache->clear();
217
+ $packager->writeToRemoteCache($cache, $ftpObj);
218
+ } else {
219
+ $cache = $this->getSconfig();
220
+ $cache->clear();
221
+ }
222
+ } catch (Exception $e) {
223
+ $this->doError($command, $e->getMessage());
224
+ }
225
+ }
226
+
227
+
228
+
229
+
230
+
231
+ }
downloader/lib/Mage/Connect/Command/Remote_Header.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ $commands = array(
28
+ 'list-upgrades' => array(
29
+ 'summary' => 'List Available Upgrades',
30
+ 'function' => 'doListUpgrades',
31
+ 'shortcut' => 'lu',
32
+ 'options' => array(
33
+ 'channelinfo' => array(
34
+ 'shortopt' => 'i',
35
+ 'doc' => 'output fully channel-aware data, even on failure',
36
+ ),
37
+ ),
38
+ 'doc' => '[preferred_state]
39
+ List releases on the server of packages you have installed where
40
+ a newer version is available with the same release state (stable etc.)
41
+ or the state passed as the second parameter.'
42
+ ),
43
+ 'list-available' => array(
44
+ 'summary' => 'List Available Packages',
45
+ 'function' => 'doListAvailable',
46
+ 'shortcut' => 'la',
47
+ 'options' => array(
48
+ 'channel' =>
49
+ array(
50
+ 'shortopt' => 'c',
51
+ 'doc' => 'specify a channel other than the default channel',
52
+ 'arg' => 'CHAN',
53
+ ),
54
+ 'channelinfo' => array(
55
+ 'shortopt' => 'i',
56
+ 'doc' => 'output fully channel-aware data, even on failure',
57
+ ),
58
+ ),
59
+ 'doc' => '
60
+ Lists the packages available on the configured server along with the
61
+ latest stable release of each package.',
62
+ ),
63
+ 'download' => array(
64
+ 'summary' => 'Download Package',
65
+ 'function' => 'doDownload',
66
+ 'shortcut' => 'd',
67
+ 'options' => array(
68
+ 'nocompress' => array(
69
+ 'shortopt' => 'Z',
70
+ 'doc' => 'download an uncompressed (.tar) file',
71
+ ),
72
+ ),
73
+ 'doc' => '<package>...
74
+ Download package tarballs. The files will be named as suggested by the
75
+ server, for example if you download the DB package and the latest stable
76
+ version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.',
77
+ ),
78
+ 'clear-cache' => array(
79
+ 'summary' => 'Clear Web Services Cache',
80
+ 'function' => 'doClearCache',
81
+ 'shortcut' => 'cc',
82
+ 'options' => array(),
83
+ 'doc' => '
84
+ Clear the XML-RPC/REST cache. See also the cache_ttl configuration
85
+ parameter.
86
+ ',
87
+ ),
88
+ );
downloader/lib/Mage/Connect/Config.php ADDED
@@ -0,0 +1,464 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+ class Mage_Connect_Config implements Iterator
27
+ {
28
+ /**
29
+ * Config file name
30
+ *
31
+ * @var string
32
+ */
33
+ protected $_configFile;
34
+
35
+ /**
36
+ * Config loaded from file
37
+ *
38
+ * @var bool
39
+ */
40
+ protected $_configLoaded;
41
+
42
+ /**
43
+ * Save file even if it not modified
44
+ *
45
+ * @var bool
46
+ */
47
+ protected $_forceSave = false;
48
+
49
+ /**
50
+ * Stores last error message
51
+ *
52
+ * @var string
53
+ */
54
+ protected $_configError = '';
55
+
56
+ const HEADER = "::ConnectConfig::v::1.0::";
57
+ const DEFAULT_DOWNLOADER_PATH = "downloader";
58
+ const DEFAULT_CACHE_PATH = ".cache";
59
+
60
+ protected $defaultProperties = array();
61
+ protected $properties = array();
62
+
63
+ /**
64
+ * Constructor loads the data from config file
65
+ * @param string $configFile
66
+ */
67
+ public function __construct($configFile = "connect.cfg")
68
+ {
69
+ $this->initProperties();
70
+ $this->_configFile = $configFile;
71
+ $this->load();
72
+ }
73
+
74
+ protected function initProperties()
75
+ {
76
+ $this->defaultProperties = array (
77
+ 'php_ini' => array(
78
+ 'type' => 'file',
79
+ 'value' => '',
80
+ 'prompt' => 'location of php.ini',
81
+ 'doc' => "It's a location of PHP.ini to use blah",
82
+ 'possible' => '/path/php.ini',
83
+ ),
84
+ 'protocol' => array(
85
+ 'type' => 'set',
86
+ 'value' => 'http',
87
+ 'prompt' => 'preffered protocol',
88
+ 'doc' => 'preffered protocol',
89
+ 'rules' => array('http', 'ftp')
90
+ ),
91
+ 'preferred_state' => array(
92
+ 'type' => 'set',
93
+ 'value' => 'stable',
94
+ 'prompt' => 'preferred package state',
95
+ 'doc' => 'preferred package state',
96
+ 'rules' => array('beta','alpha','stable','devel')
97
+ ),
98
+ 'use_custom_permissions_mode' => array (
99
+ 'type' => 'bool',
100
+ 'value' => false,
101
+ 'prompt' => 'Use custom permissions for directory and file creation',
102
+ 'doc' => 'Use custom permissions for directory and file creation',
103
+ 'possible' => 'true, false',
104
+ ),
105
+ 'global_dir_mode' => array (
106
+ 'type' => 'octal',
107
+ 'value' => 0777,
108
+ 'prompt' => 'directory creation mode',
109
+ 'doc' => 'directory creation mode',
110
+ 'possible' => '0777, 0666 etc.',
111
+ ),
112
+ 'global_file_mode' => array (
113
+ 'type' => 'octal',
114
+ 'value' => 0666,
115
+ 'prompt' => 'file creation mode',
116
+ 'doc' => 'file creation mode',
117
+ 'possible' => '0777, 0666 etc.',
118
+ ),
119
+ 'downloader_path' => array(
120
+ 'type' => 'dir',
121
+ 'value' => 'downloader',
122
+ 'prompt' => 'relative path, location of magento downloader',
123
+ 'doc' => "relative path, location of magento downloader",
124
+ 'possible' => 'path',
125
+ ),
126
+ 'magento_root' => array(
127
+ 'type' => 'dir',
128
+ 'value' => '',
129
+ 'prompt' => 'location of magento root dir',
130
+ 'doc' => "Location of magento",
131
+ 'possible' => '/path',
132
+ ),
133
+ 'root_channel_uri' => array(
134
+ 'type' => 'string',
135
+ 'value' => 'connect20.magentocommerce.com/community',
136
+ 'prompt' => '',
137
+ 'doc' => "",
138
+ 'possible' => '',
139
+ ),
140
+ 'root_channel' => array(
141
+ 'type' => 'string',
142
+ 'value' => 'community',
143
+ 'prompt' => '',
144
+ 'doc' => "",
145
+ 'possible' => '',
146
+ ),
147
+ 'remote_config' => array(
148
+ 'type' => 'string',
149
+ 'value' => '',
150
+ 'prompt' => '',
151
+ 'doc' => "",
152
+ 'possible' => 'ftp://name:password@host.com:port/path/to/folder/',
153
+ ),
154
+ 'sync_pear' => array(
155
+ 'type' => 'boolean',
156
+ 'value' => false,
157
+ 'prompt' => '',
158
+ 'doc' => "",
159
+ 'possible' => '',
160
+ )
161
+ );
162
+ $this->properties = $this->defaultProperties;
163
+ }
164
+
165
+ public function getDownloaderPath()
166
+ {
167
+ return $this->magento_root . DIRECTORY_SEPARATOR . $this->downloader_path;
168
+ }
169
+
170
+ public function getPackagesCacheDir()
171
+ {
172
+ return $this->getDownloaderPath() . DIRECTORY_SEPARATOR . self::DEFAULT_CACHE_PATH;
173
+ }
174
+
175
+ public function getChannelCacheDir($channel)
176
+ {
177
+ $channel = trim( $channel, "\\/");
178
+ return $this->getPackagesCacheDir(). DIRECTORY_SEPARATOR . $channel;
179
+ }
180
+
181
+ public function getFilename()
182
+ {
183
+ return $this->_configFile;
184
+ }
185
+
186
+ /**
187
+ * Load data from config file
188
+ *
189
+ * @return bool
190
+ */
191
+ public function load()
192
+ {
193
+ $this->_configLoaded=false;
194
+ if (!is_file($this->_configFile)) {
195
+ if (!$this->save()) {
196
+ $this->_configError = 'Config file does not exists please save Settings';
197
+ } else {
198
+ $this->_configLoaded=true;
199
+ return true;
200
+ }
201
+ return false;
202
+ }
203
+
204
+ try {
205
+ $f = fopen($this->_configFile, "r");
206
+ fseek($f, 0, SEEK_SET);
207
+ } catch (Exception $e) {
208
+ $this->_configError = "Cannot open config file {$this->_configFile} please check file permission";
209
+ return false;
210
+ }
211
+
212
+ clearstatcache();
213
+ $size = filesize($this->_configFile);
214
+ if(!$size) {
215
+ $this->_configError = "Wrong config file size {$this->_configFile} please save Settings again";
216
+ return false;
217
+ }
218
+
219
+ $headerLen = strlen(self::HEADER);
220
+ try {
221
+ $contents = fread($f, $headerLen);
222
+ if(self::HEADER != $contents) {
223
+ $this->_configError = "Wrong configuration file {$this->_configFile} please save Settings again";
224
+ return false;
225
+ }
226
+
227
+ $size -= $headerLen;
228
+ $contents = fread($f, $size);
229
+ } catch (Exception $e) {
230
+ $this->_configError = "Configuration file {$this->_configFile} read error '{$e->getMessage()}'"
231
+ . " please save Settings again";
232
+ return false;
233
+ }
234
+ $data = @unserialize($contents);
235
+ if($data === false) {
236
+ $this->_configError = "Wrong configuration file {$this->_configFile} please save Settings again";
237
+ return false;
238
+ }
239
+ foreach($data as $k=>$v) {
240
+ $this->$k = $v;
241
+ }
242
+ @fclose($f);
243
+ $this->_configLoaded=true;
244
+ }
245
+
246
+ /**
247
+ * Save config file on the disk or over ftp
248
+ *
249
+ * @return bool
250
+ */
251
+ public function store()
252
+ {
253
+ $result = false;
254
+ if ($this->_forceSave || $this->_configLoaded || strlen($this->remote_config)>0) {
255
+ $data = serialize($this->toArray());
256
+ if (strlen($this->remote_config)>0) {
257
+ //save config over ftp
258
+ $confFile = $this->downloader_path . DIRECTORY_SEPARATOR . "connect.cfg";
259
+ try {
260
+ $ftpObj = new Mage_Connect_Ftp();
261
+ $ftpObj->connect($this->remote_config);
262
+ } catch (Exception $e) {
263
+ $this->_configError = 'Cannot access to deployment FTP path. '
264
+ . 'Check deployment FTP Installation path settings.';
265
+ return $result;
266
+ }
267
+ try {
268
+ $tempFile = tempnam(sys_get_temp_dir(),'config');
269
+ $f = fopen($tempFile, "w+");
270
+ fwrite($f, self::HEADER);
271
+ fwrite($f, $data);
272
+ fclose($f);
273
+ } catch (Exception $e) {
274
+ $this->_configError = 'Cannot access to temporary file storage to save Settings.'
275
+ . 'Contact your system administrator.';
276
+ return $result;
277
+ }
278
+ try {
279
+ $result = $ftpObj->upload($confFile, $tempFile);
280
+ $ftpObj->close();
281
+ } catch (Exception $e) {
282
+ $this->_configError = 'Cannot write file over FTP. '
283
+ . 'Check deployment FTP Installation path settings.';
284
+ return $result;
285
+ }
286
+ if (!$result) {
287
+ $this->_configError = '';
288
+ }
289
+ } elseif (is_file($this->_configFile) && is_writable($this->_configFile) || is_writable(getcwd())) {
290
+ try {
291
+ $f = fopen($this->_configFile, "w+");
292
+ fwrite($f, self::HEADER);
293
+ fwrite($f, $data);
294
+ fclose($f);
295
+ $result = true;
296
+ } catch (Exception $e) {
297
+ $result = false;
298
+ }
299
+ }
300
+ }
301
+ return $result;
302
+ }
303
+
304
+ public function validate($key, $val)
305
+ {
306
+ $rules = $this->extractField($key, 'rules');
307
+ if(null === $rules) {
308
+ return true;
309
+ } elseif( is_array($rules) ) {
310
+ return in_array($val, $rules);
311
+ }
312
+ return false;
313
+ }
314
+
315
+ public function possible($key)
316
+ {
317
+ $data = $this->getKey($key);
318
+ if(! $data) {
319
+ return null;
320
+ }
321
+ if('set' == $data['type']) {
322
+ return implode("|", $data['rules']);
323
+ }
324
+ if(!empty($data['possible'])) {
325
+ return $data['possible'];
326
+ }
327
+ return "<".$data['type'].">";
328
+ }
329
+
330
+ public function type($key)
331
+ {
332
+ return $this->extractField($key, 'type');
333
+ }
334
+
335
+ public function doc($key)
336
+ {
337
+ return $this->extractField($key, 'doc');
338
+ }
339
+
340
+ public function extractField($key, $field)
341
+ {
342
+ if(!isset($this->properties[$key][$field])) {
343
+ return null;
344
+ }
345
+ return $this->properties[$key][$field];
346
+ }
347
+
348
+ public function hasKey($fld)
349
+ {
350
+ return isset($this->properties[$fld]);
351
+ }
352
+
353
+ public function getKey($fld)
354
+ {
355
+ if($this->hasKey($fld)) {
356
+ return $this->properties[$fld];
357
+ }
358
+ return null;
359
+ }
360
+
361
+ public function rewind() {
362
+ reset($this->properties);
363
+ }
364
+
365
+ public function valid() {
366
+ return current($this->properties) !== false;
367
+ }
368
+
369
+ public function key() {
370
+ return key($this->properties);
371
+ }
372
+
373
+ public function current() {
374
+ return current($this->properties);
375
+ }
376
+
377
+ public function next() {
378
+ next($this->properties);
379
+ }
380
+
381
+ public function __get($var)
382
+ {
383
+ if (isset($this->properties[$var]['value'])) {
384
+ return $this->properties[$var]['value'];
385
+ }
386
+ return null;
387
+ }
388
+
389
+ public function __set($var, $value)
390
+ {
391
+ if (is_string($value)) {
392
+ $value = trim($value);
393
+ }
394
+ if (isset($this->properties[$var])) {
395
+ if ($value === null) {
396
+ $value = '';
397
+ }
398
+ if($this->properties[$var]['value'] !== $value) {
399
+ $this->properties[$var]['value'] = $value;
400
+ $this->store();
401
+ }
402
+ }
403
+ }
404
+
405
+ public function toArray($withRules = false)
406
+ {
407
+ $out = array();
408
+ foreach($this as $k=>$v) {
409
+ $out[$k] = $withRules ? $v : $v['value'];
410
+ }
411
+ return $out;
412
+ }
413
+
414
+ /**
415
+ * Return default config value by key
416
+ *
417
+ * @param string $key
418
+ * @return mixed
419
+ */
420
+ public function getDefaultValue($key)
421
+ {
422
+ if (isset($this->defaultProperties[$key]['value'])) {
423
+ return $this->defaultProperties[$key]['value'];
424
+ }
425
+ return false;
426
+ }
427
+
428
+ /**
429
+ * Check is config loaded
430
+ *
431
+ * @return string
432
+ */
433
+ public function isLoaded()
434
+ {
435
+ return $this->_configLoaded;
436
+ }
437
+
438
+ /**
439
+ * Retrieve error message
440
+ *
441
+ * @return string
442
+ */
443
+ public function getError()
444
+ {
445
+ return $this->_configError;
446
+ }
447
+
448
+ /**
449
+ * Save config
450
+ *
451
+ * @return string
452
+ */
453
+ public function save()
454
+ {
455
+ $forceSave = $this->_forceSave;
456
+ $this->_forceSave = true;
457
+
458
+ $result = $this->store();
459
+
460
+ $this->_forceSave = $forceSave;
461
+
462
+ return $result;
463
+ }
464
+ }
downloader/lib/Mage/Connect/Converter.php ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class for convertiong old magento PEAR packages to new one
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+
35
+ final class Mage_Connect_Converter
36
+ {
37
+ protected $_archiver;
38
+
39
+ /**
40
+ *
41
+ * @return Mage_Archive
42
+ */
43
+ public function arc()
44
+ {
45
+ if(!$this->_archiver) {
46
+ $this->_archiver = new Mage_Archive();
47
+ }
48
+ return $this->_archiver;
49
+ }
50
+
51
+ public function newPackage()
52
+ {
53
+ return new Mage_Connect_Package();
54
+ }
55
+
56
+ /**
57
+ *
58
+ * @return Pear_Package_Parser_v2
59
+ */
60
+ public function oldPackageReader()
61
+ {
62
+ return new Pear_Package_Parser_v2();
63
+ }
64
+
65
+
66
+ public function __construct()
67
+ {
68
+
69
+ }
70
+
71
+
72
+ public function convertChannelName($channel)
73
+ {
74
+ return str_replace("connect.magentocommerce.com/", "", $channel);
75
+ }
76
+
77
+ /**
78
+ * Convert package dependencies - urls - by ref
79
+ * @param array $deps ref to array
80
+ * @return void
81
+ */
82
+ public function convertPackageDependencies($oldDeps)
83
+ {
84
+ $out = array();
85
+ if(empty($oldDeps['required']['package'])) {
86
+ return $out;
87
+ }
88
+ $deps = $oldDeps['required']['package'];
89
+ if(!isset($deps[0])) {
90
+ $deps = array($deps);
91
+ }
92
+ for($i=0, $c=count($deps); $i<$c; $i++) {
93
+ $deps[$i]['min_version'] = isset($deps[$i]['min']) ? $deps[$i]['min'] : false;
94
+ $deps[$i]['max_version'] = isset($deps[$i]['max']) ? $deps[$i]['max'] : false;
95
+ $deps[$i]['channel'] = $this->convertChannelName($deps[$i]['channel']);
96
+ $out[] = $deps[$i];
97
+ }
98
+
99
+ return $out;
100
+ }
101
+
102
+ public function convertLicense($oldLicense)
103
+ {
104
+ if(is_scalar($oldLicense)) {
105
+ return $oldLicense;
106
+ }
107
+ return array($oldLicense['_content'], $oldLicense['attribs']['uri']);
108
+ }
109
+
110
+ public function convertMaintainers($maintainers)
111
+ {
112
+ if(!is_array($maintainers) || !count($maintainers)) {
113
+ return array();
114
+ }
115
+ $out = array();
116
+ foreach($maintainers as $row) {
117
+ $out[] = array('name'=>$row['name'], 'email'=>$row['email'], 'user'=>'auto-converted');
118
+ }
119
+ return $out;
120
+ }
121
+
122
+ protected $fileMap = array();
123
+
124
+
125
+ /**
126
+ * Conver pear package object to magento object
127
+ * @param Pear_Package_V2 $pearObject
128
+ * @return Mage_Connect_Package
129
+ */
130
+
131
+ public function convertPackageObject($pearObject)
132
+ {
133
+ $data = array();
134
+ $mageObject = $this->newPackage();
135
+
136
+
137
+
138
+ $map = array (
139
+ 'name' => null,
140
+ 'version' => array('getterArgs' => array('release')
141
+ ),
142
+ 'package_deps' => array( 'getter'=>'getDependencies',
143
+ 'converter'=>'convertPackageDependencies',
144
+ 'setter'=>'setDependencyPackages',
145
+ ),
146
+ 'stability' => array( 'getter'=>'getState',
147
+ 'getterArgs' => array('release'),
148
+ ),
149
+ 'license' => array( 'getterArgs' => array(true),
150
+ 'converter' => 'convertLicense',
151
+ 'noArrayWrap' => true,
152
+ ),
153
+ 'summary' => null,
154
+ 'description' => null,
155
+ 'notes' => null,
156
+ 'date' => null,
157
+ 'time' => null,
158
+ 'authors' => array( 'converter' => 'convertMaintainers',
159
+ 'getter' => 'getMaintainers',
160
+ ),
161
+ 'channel' => array( 'converter' => 'convertChannelName',
162
+
163
+ ),
164
+
165
+ );
166
+ foreach($map as $field=>$rules) {
167
+
168
+ if(empty($rules)) {
169
+ $rules = array('setter'=> '', 'getter'=> '');
170
+ }
171
+
172
+ if(empty($rules['getter'])) {
173
+ $rules['getter'] = 'get'. ucfirst($field);
174
+ }
175
+
176
+ $useSetter = empty($rules['noSetter']);
177
+ $useGetter = empty($rules['noGetter']);
178
+
179
+
180
+ if(empty($rules['setter'])) {
181
+ $rules['setter'] = 'set'. ucfirst($field);
182
+ }
183
+ if(empty($rules['getterArgs'])) {
184
+ $rules['getterArgs'] = array();
185
+ } elseif(!is_array($rules['getterArgs'])) {
186
+ throw new Exception("Invalid 'getterArgs' for '{$field}', should be array");
187
+ }
188
+
189
+ if($useGetter && !method_exists($pearObject, $rules['getter'])) {
190
+ $mName = get_class($pearObject)."::".$rules['getter'];
191
+ throw new Exception('No getter method exists: '.$mName);
192
+ }
193
+
194
+ if($useSetter && !method_exists($mageObject, $rules['setter'])) {
195
+ $mName = get_class($mageObject)."::".$rules['setter'];
196
+ throw new Exception('No setter method exists: '.$mName);
197
+ }
198
+
199
+ $useConverter = !empty($rules['converter']);
200
+
201
+ if($useConverter && false === method_exists($this, $rules['converter'])) {
202
+ $mName = get_class($this)."::".$rules['converter'];
203
+ throw new Exception('No converter method exists: '.$mName);
204
+ }
205
+
206
+ if($useGetter) {
207
+ $getData = call_user_func_array(array($pearObject, $rules['getter']), $rules['getterArgs']);
208
+ } else {
209
+ $getData = array();
210
+ }
211
+
212
+ if($useConverter) {
213
+ $args = array();
214
+ if(!$useGetter && !$useSetter) {
215
+ $args = array($pearObject, $mageObject);
216
+ } elseif(!$useSetter) {
217
+ $args = array($mageObject, $getData);
218
+ } else {
219
+ $args = array($getData);
220
+ }
221
+ $getData = call_user_func_array(array($this, $rules['converter']), $args);
222
+ }
223
+
224
+ $noWrap = !empty($rules['noArrayWrap']);
225
+ if($useSetter) {
226
+ $setData = call_user_func_array(array($mageObject, $rules['setter']), $noWrap ? $getData : array($getData));
227
+ }
228
+ }
229
+ return $mageObject;
230
+ }
231
+
232
+ /**
233
+ * Convert PEAR package to Magento package
234
+ * @param string $sourceFile path to PEAR .tgz
235
+ * @param string|false $destFile path to newly-created Magento .tgz, false to specify auto
236
+ * @return bool
237
+ */
238
+ public function convertPearToMage($sourceFile, $destFile = false)
239
+ {
240
+ try {
241
+ if(!file_exists($sourceFile)) {
242
+ throw new Exception("File doesn't exist: {$sourceFile}");
243
+ }
244
+ $arc = $this->arc();
245
+ $tempDir = "tmp-".basename($sourceFile).uniqid();
246
+ $outDir = "out-".basename($sourceFile).uniqid();
247
+ $outDir = rtrim($outDir, "\\/");
248
+ Mage_System_Dirs::mkdirStrict($outDir);
249
+ Mage_System_Dirs::mkdirStrict($tempDir);
250
+
251
+ $result = $arc->unpack($sourceFile, $tempDir);
252
+ if(!$result) {
253
+ throw new Exception("'{$sourceFile}' was not unpacked");
254
+ }
255
+
256
+ $result = rtrim($result, "\\/");
257
+ $packageXml = $result . DS . "package.xml";
258
+ if(!file_exists($packageXml)) {
259
+ throw new Exception("No package.xml found inside '{$sourceFile}'");
260
+ }
261
+
262
+ $reader = $this->oldPackageReader();
263
+ $data = file_get_contents($packageXml);
264
+
265
+ $pearObject = $reader->parsePackage($data, $packageXml);
266
+ $mageObject = $this->convertPackageObject($pearObject);
267
+ if(!$mageObject->validate()) {
268
+ throw new Exception("Package validation failed.\n". implode("\n", $mageObject->getErrors()));
269
+ }
270
+
271
+ /**
272
+ * Calculate destination file if false
273
+ */
274
+ if(false === $destFile) {
275
+ $pathinfo = pathinfo($sourceFile);
276
+ $destFile = $pathinfo['dirname'] . DS .$pathinfo['filename'].'-converted';
277
+ if(isset($pathinfo['extension'])) {
278
+ $destFile .= ".".$pathinfo['extension'];
279
+ }
280
+ }
281
+
282
+ $target = new Mage_Connect_Package_Target("target.xml");
283
+ $targets = $target->getTargets();
284
+ $mageObject->setTarget($target);
285
+ $validRoles = array_keys($targets);
286
+ $data = $pearObject->getFilelist();
287
+ $pathSource = dirname($pearObject->getPackageFile()).DS.$pearObject->getName()."-".$pearObject->getVersion();
288
+
289
+ $filesToDo = array();
290
+ foreach($data as $file =>$row) {
291
+ $name = $row['name'];
292
+ $role = $row['role'];
293
+ if(!in_array($role, $validRoles)) {
294
+ $role = 'mage';
295
+ }
296
+ $baseName = ltrim($targets[$role], "\\/.");
297
+ $baseName = rtrim($baseName, "\\/");
298
+ $sourceFile = $pathSource.DS.$name;
299
+ $targetFile = $outDir . DS . $baseName . DS. $name;
300
+ if(file_exists($sourceFile)) {
301
+ Mage_System_Dirs::mkdirStrict(dirname($targetFile));
302
+ $copy = @copy($sourceFile, $targetFile);
303
+ if(false === $copy) {
304
+ throw new Exception("Cannot copy '{$sourceFile}' to '{$targetFile}'");
305
+ }
306
+ }
307
+ $filesToDo[] = array ('name'=> $name, 'role'=>$role);
308
+ }
309
+ $cwd = getcwd();
310
+ @chdir($outDir);
311
+ foreach($filesToDo as $fileToDo) {
312
+ $mageObject->addContent($fileToDo['name'], $fileToDo['role']);
313
+ }
314
+ $mageObject->save(getcwd());
315
+ @chdir($cwd);
316
+ $filename = $outDir. DS . $mageObject->getReleaseFilename().".tgz";
317
+ if(@file_exists($targetArchive)) {
318
+ @unlink($targetArchive);
319
+ }
320
+ Mage_System_Dirs::mkdirStrict(dirname($destFile));
321
+ $copy = @copy($filename, $destFile);
322
+ if(false === $copy) {
323
+ throw new Exception("Cannot copy '{$filename}' to '{$targetArchive}'");
324
+ }
325
+ Mage_System_Dirs::rm($tempDir);
326
+ Mage_System_Dirs::rm($outDir);
327
+
328
+ } catch (Exception $e) {
329
+ throw $e;
330
+ }
331
+ return $destFile;
332
+ }
333
+
334
+
335
+
336
+ }
downloader/lib/Mage/Connect/Frontend.php ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ class Mage_Connect_Frontend
28
+ {
29
+
30
+ /**
31
+ * Silent flag. If set no output is produced to view.
32
+ * Should be used in derived classes.
33
+ * @var bool
34
+ */
35
+ protected $_silent = false;
36
+
37
+ /**
38
+ * Capture mode. If set command output should be collected
39
+ * by derived class impplementation
40
+ * @var bool
41
+ */
42
+ protected $_capture = false;
43
+
44
+
45
+ /**
46
+ * push/pop variable for capture
47
+ * @var array
48
+ */
49
+ protected $_captureSaved = array();
50
+
51
+ /**
52
+ * push/pop variable for silent
53
+ * @var array
54
+ */
55
+ protected $_silentSaved = array();
56
+
57
+ /**
58
+ * Errors list
59
+ * @var array
60
+ */
61
+ protected $_errors = array();
62
+
63
+ /**
64
+ * Add error to errors list
65
+ * @param mixed $data
66
+ * @return void
67
+ */
68
+ public function addError($data)
69
+ {
70
+ $this->_errors[] = $data;
71
+ }
72
+
73
+ /**
74
+ * Get errors, clear errors list with first param
75
+ * @param bool $clear
76
+ * @return array
77
+ */
78
+ public function getErrors($clear = true)
79
+ {
80
+ if(!$clear) {
81
+ return $this->_errors;
82
+ }
83
+ $out = $this->_errors;
84
+ $this->clearErrors();
85
+ return $out;
86
+ }
87
+
88
+ /**
89
+ * Clear errors array
90
+ * @return void
91
+ */
92
+ public function clearErrors()
93
+ {
94
+ $this->_errors = array();
95
+ }
96
+
97
+ /**
98
+ * Are there any errros?
99
+ * @return bool
100
+ */
101
+ public function hasErrors()
102
+ {
103
+ return count($this->_errors) != 0;
104
+ }
105
+
106
+ /**
107
+ * Error processing
108
+ * @param string $command
109
+ * @param stting $message
110
+ * @return void
111
+ */
112
+ public function doError($command, $message)
113
+ {
114
+ $this->addError(array($command, $message));
115
+ }
116
+
117
+ /**
118
+ * Save capture state
119
+ * @return Mage_Connect_Frontend
120
+ */
121
+ public function pushCapture()
122
+ {
123
+ array_push($this->_captureSaved, $this->_capture);
124
+ return $this;
125
+ }
126
+
127
+ /**
128
+ * Restore capture state
129
+ * @return Mage_Connect_Frontend
130
+ */
131
+ public function popCapture()
132
+ {
133
+ $this->_capture = array_pop($this->_captureSaved);
134
+ return $this;
135
+ }
136
+
137
+ /**
138
+ * Set capture mode
139
+ * @param bool $arg true by default
140
+ * @return Mage_Connect_Frontend
141
+ */
142
+ public function setCapture($arg = true)
143
+ {
144
+ $this->_capture = $arg;
145
+ return $this;
146
+ }
147
+
148
+ /**
149
+ * Getter for capture mode
150
+ * @return bool
151
+ */
152
+ public function isCapture()
153
+ {
154
+ return $this->_capture;
155
+ }
156
+
157
+ /**
158
+ * Log stub
159
+ * @param $msg
160
+ * @return
161
+ */
162
+ public function log($msg)
163
+ {
164
+
165
+ }
166
+
167
+ /**
168
+ * Ouptut method
169
+ * @param array $data
170
+ * @return void
171
+ */
172
+ public function output($data)
173
+ {
174
+
175
+ }
176
+
177
+ /**
178
+ * Get instance of derived class
179
+ *
180
+ * @param $class CLI for example will produce Mage_Connect_Frontend_CLI
181
+ * @return object
182
+ */
183
+ public static function getInstance($class)
184
+ {
185
+ $class = __CLASS__."_".$class;
186
+ return new $class();
187
+ }
188
+
189
+ /**
190
+ * Get output if capture mode set
191
+ * Clear prevoius if needed
192
+ * @param bool $clearPrevious
193
+ * @return mixed
194
+ */
195
+ public function getOutput($clearPrevious = true)
196
+ {
197
+
198
+ }
199
+
200
+
201
+ /**
202
+ * Save silent mode
203
+ * @return Mage_Connect_Frontend
204
+ */
205
+ public function pushSilent()
206
+ {
207
+ array_push($this->_silentSaved, $this->_silent);
208
+ return $this;
209
+ }
210
+
211
+ /**
212
+ * Restore silent mode
213
+ * @return Mage_Connect_Frontend
214
+ */
215
+ public function popSilent()
216
+ {
217
+ $this->_silent = array_pop($this->_silentSaved);
218
+ return $this;
219
+ }
220
+
221
+ /**
222
+ * Set silent mode
223
+ * @param bool $value
224
+ * @return Mage_Connect_Frontend
225
+ */
226
+ public function setSilent($value = true)
227
+ {
228
+ $this->_silent = (bool) $value;
229
+ return $this;
230
+ }
231
+
232
+ /**
233
+ * Is silent mode?
234
+ * @return bool
235
+ */
236
+ public function isSilent()
237
+ {
238
+ return (bool) $this->_silent;
239
+ }
240
+
241
+ /**
242
+ * Method for ask client about rewrite all files.
243
+ *
244
+ * @param $string
245
+ */
246
+ public function confirm($string)
247
+ {
248
+
249
+ }
250
+ }
251
+
downloader/lib/Mage/Connect/Frontend/CLI.php ADDED
@@ -0,0 +1,456 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * CLI Frontend implementation
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+
35
+ class Mage_Connect_Frontend_CLI
36
+ extends Mage_Connect_Frontend
37
+ {
38
+
39
+ /**
40
+ * Collected output
41
+ * @var array
42
+ */
43
+ protected $_output = array();
44
+
45
+ /**
46
+ * Output error
47
+ * @param string $command
48
+ * @param string $message
49
+ * @return void
50
+ */
51
+ public function doError($command, $message)
52
+ {
53
+ parent::doError($command, $message);
54
+ $this->writeln("Error: ");
55
+ $this->writeln("$command: $message");
56
+ }
57
+
58
+
59
+ /**
60
+ * Output config help
61
+ * @param array $data
62
+ * @return void
63
+ */
64
+ public function outputConfigHelp($data)
65
+ {
66
+ foreach($data['data'] as $k=>$v) {
67
+ if(is_scalar($v)) {
68
+ $this->writeln($v);
69
+ } elseif(is_array($v)) {
70
+ $this->writeln(implode(": ", $v));
71
+ }
72
+ }
73
+ }
74
+
75
+
76
+ /**
77
+ * Output info
78
+ * @param array $data
79
+ * @return void
80
+ */
81
+ public function outputRemoteInfo($data)
82
+ {
83
+ if(!is_array($data['releases'])) {
84
+ return;
85
+ }
86
+ foreach ($data['releases'] as $r) {
87
+ $this->writeln(implode(" ", $r));
88
+ }
89
+ }
90
+
91
+
92
+ public function detectMethodByType($type)
93
+ {
94
+ $defaultMethod = "output";
95
+ $methodMap = array(
96
+ 'list-upgrades'=> 'outputUpgrades',
97
+ 'list-available' => 'outputChannelsPackages',
98
+ 'list-installed' => 'writeInstalledList',
99
+ 'package-dependencies' => 'outputPackageDeps',
100
+ 'package-prepare' => 'outputPackagePrepare',
101
+ 'list-files' => 'outputPackageContents',
102
+ 'config-help' => 'outputConfigHelp',
103
+ 'info' => 'outputRemoteInfo',
104
+ 'config-show' => 'outputConfig',
105
+ 'install' => 'outputInstallResult',
106
+ 'install-file' => 'outputInstallResult',
107
+ 'upgrade' => 'outputInstallResult',
108
+ 'upgrade-all' => 'outputInstallResult',
109
+ 'uninstall' => 'outputDeleted',
110
+ 'list-channels' => 'outputListChannels',
111
+ );
112
+ if(isset($methodMap[$type])) {
113
+ return $methodMap[$type];
114
+ }
115
+ return $defaultMethod;
116
+ }
117
+
118
+
119
+ public function outputDeleted($data)
120
+ {
121
+ if(!count($data['data'])) {
122
+ return;
123
+ }
124
+ $this->writeln($data['title']);
125
+ foreach($data['data'] as $row) {
126
+ $this->writeln("$row[0]/$row[1]");
127
+ }
128
+ }
129
+
130
+ public function outputListChannels($data)
131
+ {
132
+ $this->writeln($data['title']);
133
+
134
+ $channels =& $data['data'][Mage_Connect_Singleconfig::K_CHAN];
135
+ foreach($channels as $name => $v) {
136
+ $this->writeln("$name: {$v[Mage_Connect_Singleconfig::K_URI]}");
137
+ }
138
+ $aliases =& $data['data'][Mage_Connect_Singleconfig::K_CHAN_ALIAS];
139
+ if(count($aliases)) {
140
+ $this->writeln();
141
+ $this->writeln($data['title_aliases']);
142
+ foreach($aliases as $k=>$v) {
143
+ $this->writeln("$k => $v");
144
+ }
145
+ }
146
+
147
+ }
148
+
149
+ /**
150
+ * Output install result
151
+ * @param array $data
152
+ * @return void
153
+ */
154
+ public function outputInstallResult($data)
155
+ {
156
+ if(isset($data['title'])) {
157
+ $title = trim($data['title'])." ";
158
+ } else {
159
+ $title = '';
160
+ }
161
+ foreach($data['assoc'] as $row) {
162
+ $this->printf("%s%s/%s %s\n", $title, $row['channel'], $row['name'], $row['version']);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Ouptut package contents
168
+ * @param array $data
169
+ * @return void
170
+ */
171
+ public function outputPackageContents($data)
172
+ {
173
+ $this->writeln($data['title']);
174
+ foreach($data['data'] as $file) {
175
+ $this->writeln($file);
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Output package dependencies
181
+ * @param $data
182
+ * @return void
183
+ */
184
+ public function outputPackageDeps($data)
185
+ {
186
+ $title = $data['title'];
187
+ $this->writeln($title);
188
+ foreach($data['data'] as $package) {
189
+ $this->printf("%-20s %-20s %-20s %-20s\n", $package['channel'], $package['name'], $package['min'], $package['max']);
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Output package prepare
195
+ * @param $data
196
+ * @return void
197
+ */
198
+ public function outputPackagePrepare($data)
199
+ {
200
+ $title = $data['title'];
201
+ $this->writeln($title);
202
+ foreach($data['data'] as $package) {
203
+ $this->printf("%-20s %-20s %-20s %-20s\n", $package['channel'], $package['name'], $package['version'], $package['install_state']);
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Ouptut channel packages
209
+ * @param $data
210
+ * @return unknown_type
211
+ */
212
+ public function outputChannelsPackages($data)
213
+ {
214
+ foreach($data['data'] as $channelInfo) {
215
+ $title =& $channelInfo['title'];
216
+ $packages =& $channelInfo['packages'];
217
+ $this->writeln($title);
218
+ foreach($packages as $name=>$package) {
219
+ $releases =& $package['releases'];
220
+ $tmp = array();
221
+ foreach($releases as $ver=>$state) {
222
+ $tmp[] = "$ver $state";
223
+ }
224
+ $tmp = implode(',',$tmp);
225
+ $this->writeln($name.": ".$tmp);
226
+ }
227
+ }
228
+ }
229
+
230
+
231
+ /**
232
+ * Make output
233
+ *
234
+ * @param array $data
235
+ * @return void
236
+ */
237
+
238
+ public function output($data)
239
+ {
240
+ $capture = $this->isCapture();
241
+ if($capture) {
242
+ $this->_output[] = $data;
243
+ return;
244
+ }
245
+
246
+ if(is_array($data)) {
247
+ foreach($data as $type=>$params) {
248
+ $method = $this->detectMethodByType($type);
249
+ if($method) {
250
+ $this->$method($params);
251
+ } else {
252
+ $this->writeln(__METHOD__." handler not found for {$type}");
253
+ }
254
+ }
255
+ } else {
256
+ $this->writeln($data);
257
+ }
258
+ }
259
+
260
+
261
+ /**
262
+ * Detailed package info
263
+ * @param Mage_Connect_Package $package
264
+ * @return void
265
+ */
266
+ public function outputPackage($package)
267
+ {
268
+ $fields = array(
269
+ 'Name'=>'name',
270
+ 'Version'=>'version',
271
+ 'Stability'=>'stability',
272
+ 'Description' => 'description',
273
+ 'Date' => 'date',
274
+ 'Authors' => 'authors',
275
+ );
276
+
277
+ foreach($fields as $title => $fld) {
278
+ $method = "get".ucfirst($fld);
279
+ $data = $package->$method();
280
+ if(empty($data)) {
281
+ continue;
282
+ }
283
+ $this->write($title.": ");
284
+ if(is_array($data)) {
285
+ $this->write(print_r($data,true));
286
+ } else {
287
+ $this->write($data);
288
+ }
289
+ $this->writeln('');
290
+ }
291
+ }
292
+
293
+
294
+ /**
295
+ * Write channels list
296
+ * @param array $data
297
+ * @return void
298
+ */
299
+ public function writeChannelsList($data)
300
+ {
301
+ $this->writeln("Channels available: ");
302
+ $this->writeln("===================");
303
+ $out = $data['byName'];
304
+ ksort($out);
305
+ foreach($out as $k=>$v) {
306
+ $this->printf ("%-20s %-20s\n", $k, $v);
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Write installed list
312
+ * @param array $data
313
+ * @return void
314
+ */
315
+ public function writeInstalledList($data)
316
+ {
317
+ $totalCount = 0;
318
+ foreach($data['data'] as $channel=>$packages) {
319
+ $title = sprintf($data['channel-title'], $channel);
320
+ $c = count($packages);
321
+ $totalCount += $c;
322
+ if(!$c) {
323
+ continue;
324
+ }
325
+ $this->writeln($title);
326
+ foreach($packages as $name=>$row) {
327
+ $this->printf("%-20s %-20s\n", $name, $row['version']." ".$row['stability']);
328
+ }
329
+ }
330
+ if($totalCount === 0) {
331
+ $this->writeln("No installed packages");
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Output commands list
337
+ * @param array $data
338
+ * @return void
339
+ */
340
+ public function outputCommandList($data)
341
+ {
342
+ $this->writeln("Connect commands available:");
343
+ $this->writeln("===========================");
344
+ foreach ($data as $k=>$v) {
345
+ $this->printf ("%-20s %-20s\n", $k, $v['summary']);
346
+ }
347
+ }
348
+
349
+ /**
350
+ * Output config
351
+ * @param array $data
352
+ * @return void
353
+ */
354
+ public function outputConfig($data)
355
+ {
356
+ foreach($data['data'] as $name=>$row) {
357
+ $value = $row['value'] === '' ? "<not set>" : strval($row['value']);
358
+ $this->printf("%-30s %-20s %-20s\n", $row['prompt'], $name, $value);
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Output config variable
364
+ * @param string $key
365
+ * @param string $value
366
+ * @return void
367
+ */
368
+ public function outputConfigVariable($key, $value)
369
+ {
370
+ if($value === '') {
371
+ $value = '<not set>';
372
+ }
373
+ $this->writeln("Config variable '{$key}': {$value}");
374
+ }
375
+
376
+ /**
377
+ * Write data and "\n" afterwards
378
+ * @param string $data
379
+ * @return void
380
+ */
381
+ public function writeln($data = '')
382
+ {
383
+ $this->write($data."\n");
384
+ }
385
+
386
+
387
+ /**
388
+ * get output, clear if needed
389
+ *
390
+ * @param bool $clearPrevoius optional, true by default
391
+ * @return array
392
+ */
393
+ public function getOutput($clearPrevious = true)
394
+ {
395
+ $out = $this->_output;
396
+ if($clearPrevious) {
397
+ $this->_output = array();
398
+ }
399
+ return $out;
400
+ }
401
+
402
+ /**
403
+ * Write data to console
404
+ * @param string $data
405
+ * @return void
406
+ */
407
+ public function write($data)
408
+ {
409
+ if($this->isSilent()) {
410
+ return;
411
+ }
412
+ print $data;
413
+ }
414
+
415
+ /**
416
+ * Output printf-stlye formatted string and args
417
+ * @return void
418
+ */
419
+ public function printf()
420
+ {
421
+ $args = func_get_args();
422
+ $this->write(call_user_func_array('sprintf', $args));
423
+ }
424
+
425
+ /**
426
+ * Readline from console
427
+ * @return string
428
+ */
429
+ public function readln()
430
+ {
431
+ $out = "";
432
+ $key = fgetc(STDIN);
433
+ while ($key!="\n") {
434
+ $out.= $key;
435
+ $key = fread(STDIN, 1);
436
+ }
437
+ return $out;
438
+ }
439
+
440
+ /**
441
+ * Output upgrades
442
+ * @param array $data
443
+ * @return void
444
+ */
445
+ public function outputUpgrades($data)
446
+ {
447
+ foreach($data['data'] as $chan => $packages) {
448
+ $this->writeln("Updates for ".$chan.": ");
449
+ foreach($packages as $name => $data) {
450
+ $this->writeln(" $name: {$data['from']} => {$data['to']}");
451
+ }
452
+ }
453
+ }
454
+
455
+ }
456
+
downloader/lib/Mage/Connect/Ftp.php ADDED
@@ -0,0 +1,523 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to work with remote FTP server
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Connect_Ftp
35
+ {
36
+
37
+ /**
38
+ * Connection object
39
+ * @var resource
40
+ */
41
+ protected $_conn = false;
42
+
43
+ public function __construct()
44
+ {
45
+
46
+ }
47
+
48
+ /**
49
+ * Check connected, throw exception if not
50
+ * @throws Exception
51
+ * @return void
52
+ */
53
+ protected function checkConnected()
54
+ {
55
+ if(!$this->_conn) {
56
+ throw new Exception(__CLASS__." - no connection established with server");
57
+ }
58
+ }
59
+
60
+ /**
61
+ * ftp_mkdir wrapper
62
+ * @param stin$name
63
+ * @return unknown_type
64
+ */
65
+ public function mdkir($name)
66
+ {
67
+ $this->checkConnected();
68
+ return @ftp_mkdir($this->_conn, $name);
69
+ }
70
+
71
+
72
+
73
+ /**
74
+ * Make dir recursive
75
+ * @param string $path
76
+ * @param int $mode
77
+ */
78
+ public function mkdirRecursive($path, $mode = 0777)
79
+ {
80
+ $this->checkConnected();
81
+ $dir = explode('/', $path);
82
+ $path= "";
83
+ $ret = true;
84
+ for ($i=0; $i < count($dir); $i++) {
85
+ $path .= "/" .$dir[$i];
86
+ if(!@ftp_chdir($this->_conn, $path)) {
87
+ @ftp_chdir($this->_conn,"/");
88
+ if(!@ftp_mkdir($this->_conn,$path)) {
89
+ $ret=false;
90
+ break;
91
+ } else {
92
+ @ftp_chmod($this->_conn, $mode, $path);
93
+ }
94
+ }
95
+ }
96
+ return $ret;
97
+ }
98
+
99
+
100
+ /**
101
+ * Try to login to server
102
+ * @param string $login
103
+ * @param string $password
104
+ * @throws Exception on invalid login credentials
105
+ * @return bool
106
+ */
107
+ public function login($login = "anonymous", $password = "test@gmail.com")
108
+ {
109
+ $this->checkConnected();
110
+ $res = @ftp_login($this->_conn, $login, $password);
111
+ if(!$res) {
112
+ throw new Exception("Invalid login credentials");
113
+ }
114
+ return $res;
115
+ }
116
+
117
+ /**
118
+ * Validate connection string
119
+ * @param string $string
120
+ * @throws Exception
121
+ * @return string
122
+ */
123
+ public function validateConnectionString($string)
124
+ {
125
+ if (empty($string)) {
126
+ throw new Exception("Connection string is empty");
127
+ }
128
+ $data = @parse_url($string);
129
+ if(false === $data) {
130
+ throw new Exception("Connection string invalid: '{$string}'");
131
+ }
132
+ if($data['scheme'] != 'ftp') {
133
+ throw new Exception("Support for scheme '{$data['scheme']}' unsupported");
134
+ }
135
+ return $data;
136
+ }
137
+
138
+ /**
139
+ * Connect to server using connect string
140
+ * Connection string: ftp://user:pass@server:port/path
141
+ * user,pass,port,path are optional parts
142
+ * @param string $string
143
+ *
144
+ * @param $timeout
145
+ * @return unknown_type
146
+ */
147
+ public function connect($string, $timeout = 90)
148
+ {
149
+ $params = $this->validateConnectionString($string);
150
+ $port = isset($params['port']) ? intval($params['port']) : 21;
151
+
152
+ $this->_conn = @ftp_connect($params['host'], $port, $timeout);
153
+
154
+ if(!$this->_conn) {
155
+ throw new Exception("Cannot connect to host: {$params['host']}");
156
+ }
157
+ ftp_pasv($this->_conn, true);
158
+ if(isset($params['user']) && isset($params['pass'])) {
159
+ $this->login($params['user'], $params['pass']);
160
+ } else {
161
+ $this->login();
162
+ }
163
+ if(isset($params['path'])) {
164
+ if(!$this->chdir($params['path'])) {
165
+ throw new Exception ("Cannot chdir after login to: {$params['path']}");
166
+ }
167
+ }
168
+ }
169
+
170
+ /**
171
+ * ftp_fput wrapper
172
+ * @param string $remoteFile
173
+ * @param resource $handle
174
+ * @param int $mode FTP_BINARY | FTP_ASCII
175
+ * @param int $startPos
176
+ * @return bool
177
+ */
178
+
179
+ public function fput($remoteFile, $handle, $mode = FTP_BINARY, $startPos = 0)
180
+ {
181
+ $this->checkConnected();
182
+ return @ftp_fput($this->_conn, $remoteFile, $handle, $mode, $startPos);
183
+ }
184
+
185
+ /**
186
+ * ftp_put wrapper
187
+ * @param string $remoteFile
188
+ * @param string $localFile
189
+ * @param int $mode FTP_BINARY | FTP_ASCII
190
+ * @param int $startPos
191
+ * @return bool
192
+ */
193
+ public function put($remoteFile, $localFile, $mode = FTP_BINARY, $startPos = 0)
194
+ {
195
+ $this->checkConnected();
196
+ return @ftp_put($this->_conn, $remoteFile, $localFile, $mode, $startPos);
197
+ }
198
+
199
+
200
+ /**
201
+ * Get current working directory
202
+ * @return mixed
203
+ */
204
+ public function getcwd()
205
+ {
206
+ $d = $this->raw("pwd");
207
+ $data = explode(" ", $d[0], 3);
208
+ if(empty($data[1])) {
209
+ return false;
210
+ }
211
+ if(intval($data[0]) != 257) {
212
+ return false;
213
+ }
214
+ $out = trim($data[1], '"');
215
+ if($out !== "/") {
216
+ $out = rtrim($out, "/");
217
+ }
218
+ return $out;
219
+ }
220
+
221
+ /**
222
+ * ftp_raw wrapper
223
+ * @param string $cmd
224
+ * @return mixed
225
+ */
226
+ public function raw($cmd)
227
+ {
228
+ $this->checkConnected();
229
+ return @ftp_raw($this->_conn, $cmd);
230
+ }
231
+
232
+
233
+ /**
234
+ * Upload local file to remote
235
+ *
236
+ * Can be used for relative and absoulte remote paths
237
+ * Relative: use chdir before calling this
238
+ *
239
+ * @param srting $remote
240
+ * @param string $local
241
+ * @param int $dirMode
242
+ * @param int $fileMode
243
+ * @return bool
244
+ */
245
+ public function upload($remote, $local, $dirMode = 0777, $fileMode=0)
246
+ {
247
+ $this->checkConnected();
248
+
249
+ if(!file_exists($local)) {
250
+ throw new Exception("Local file doesn't exist: {$local}");
251
+ }
252
+ if(!is_readable($local)) {
253
+ throw new Exception("Local file is not readable: {$local}");
254
+ }
255
+ if(is_dir($local)) {
256
+ throw new Exception("Directory given instead of file: {$local}");
257
+ }
258
+
259
+ $globalPathMode = substr($remote, 0, 1) == "/";
260
+ $dirname = dirname($remote);
261
+ $cwd = $this->getcwd();
262
+ if(false === $cwd) {
263
+ throw new Exception("Server returns something awful on PWD command");
264
+ }
265
+
266
+ if(!$globalPathMode) {
267
+ $dirname = $cwd."/".$dirname;
268
+ $remote = $cwd."/".$remote;
269
+ }
270
+ $res = $this->mkdirRecursive($dirname, $dirMode);
271
+ $this->chdir($cwd);
272
+
273
+ if(!$res) {
274
+ return false;
275
+ }
276
+ $res = $this->put($remote, $local);
277
+
278
+ if(!$res) {
279
+ return false;
280
+ }
281
+
282
+ if($fileMode){
283
+ $res=$this->chmod($fileMode, $remote);
284
+ }
285
+ return (bool)$res;
286
+ }
287
+
288
+ /**
289
+ * Download remote file to local machine
290
+ * @param string $remote
291
+ * @param string $local
292
+ * @param int $ftpMode FTP_BINARY|FTP_ASCII
293
+ * @return bool
294
+ */
295
+ public function download($remote, $local, $ftpMode = FTP_BINARY)
296
+ {
297
+ $this->checkConnected();
298
+ return $this->get($local, $remote, $ftpMode);
299
+ }
300
+
301
+
302
+ /**
303
+ * ftp_pasv wrapper
304
+ * @param bool $pasv
305
+ * @return bool
306
+ */
307
+ public function pasv($pasv)
308
+ {
309
+ $this->checkConnected();
310
+ return @ftp_pasv($this->_conn, (bool) $pasv);
311
+ }
312
+
313
+ /**
314
+ * Close FTP connection
315
+ * @return void
316
+ */
317
+ public function close()
318
+ {
319
+ if($this->_conn) {
320
+ @ftp_close($this->_conn);
321
+ }
322
+ }
323
+
324
+ /**
325
+ * ftp_chmod wrapper
326
+ * @param $mode
327
+ * @param $remoteFile
328
+ * @return bool
329
+ */
330
+ public function chmod($mode, $remoteFile)
331
+ {
332
+ $this->checkConnected();
333
+ return @ftp_chmod($this->_conn, $mode, $remoteFile);
334
+ }
335
+
336
+ /**
337
+ * ftp_chdir wrapper
338
+ * @param string $dir
339
+ * @return bool
340
+ */
341
+ public function chdir($dir)
342
+ {
343
+ $this->checkConnected();
344
+ return @ftp_chdir($this->_conn, $dir);
345
+ }
346
+
347
+ /**
348
+ * ftp_cdup wrapper
349
+ * @return bool
350
+ */
351
+ public function cdup()
352
+ {
353
+ $this->checkConnected();
354
+ return @ftp_cdup($this->_conn);
355
+ }
356
+
357
+ /**
358
+ * ftp_get wrapper
359
+ * @param string $localFile
360
+ * @param string $remoteFile
361
+ * @param int $fileMode FTP_BINARY | FTP_ASCII
362
+ * @param int $resumeOffset
363
+ * @return bool
364
+ */
365
+ public function get($localFile, $remoteFile, $fileMode = FTP_BINARY, $resumeOffset = 0)
366
+ {
367
+ $remoteFile = $this->correctFilePath($remoteFile);
368
+ $this->checkConnected();
369
+ return @ftp_get($this->_conn, $localFile, $remoteFile, $fileMode, $resumeOffset);
370
+ }
371
+
372
+ /**
373
+ * ftp_nlist wrapper
374
+ * @param string $dir
375
+ * @return bool
376
+ */
377
+ public function nlist($dir = "/")
378
+ {
379
+ $this->checkConnected();
380
+ $dir = $this->correctFilePath($dir);
381
+ return @ftp_nlist($this->_conn, $dir);
382
+ }
383
+
384
+ /**
385
+ * ftp_rawlist wrapper
386
+ * @param string $dir
387
+ * @param bool $recursive
388
+ * @return mixed
389
+ */
390
+ public function rawlist( $dir = "/", $recursive = false )
391
+ {
392
+ $this->checkConnected();
393
+ $dir = $this->correctFilePath($dir);
394
+ return @ftp_rawlist($this->_conn, $dir, $recursive);
395
+ }
396
+
397
+
398
+ /**
399
+ * Convert byte count to float KB/MB format
400
+ * @param int $bytes
401
+ * @return string
402
+ */
403
+ public static function byteconvert($bytes)
404
+ {
405
+ $symbol = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
406
+ $exp = floor( log($bytes) / log(1024) );
407
+ return sprintf( '%.2f ' . $symbol[ $exp ], ($bytes / pow(1024, floor($exp))) );
408
+ }
409
+
410
+ /**
411
+ * Chmod string "-rwxrwxrwx" to "777" converter
412
+ * @param string $chmod
413
+ * @return string
414
+ */
415
+ public static function chmodnum($chmod)
416
+ {
417
+ $trans = array('-' => '0', 'r' => '4', 'w' => '2', 'x' => '1');
418
+ $chmod = substr(strtr($chmod, $trans), 1);
419
+ $array = str_split($chmod, 3);
420
+ return array_sum(str_split($array[0])) . array_sum(str_split($array[1])) . array_sum(str_split($array[2]));
421
+ }
422
+
423
+ /**
424
+ * Checks file exists
425
+ *
426
+ * @param string $path
427
+ * @param bool $excludeIfIsDir
428
+ * @return bool
429
+ */
430
+ public function fileExists($path, $excludeIfIsDir = true)
431
+ {
432
+ $path = $this->correctFilePath($path);
433
+ $globalPathMode = substr($path, 0, 1) == "/";
434
+
435
+ $file = basename($path);
436
+ $dir = $globalPathMode ? dirname($path) : $this->getcwd()."/".($path==basename($path)?'':$path);
437
+ $data = $this->ls($dir);
438
+ foreach($data as $row) {
439
+ if($file == basename($row['name'])) {
440
+ if($excludeIfIsDir && $row['dir']) {
441
+ continue;
442
+ }
443
+ return true;
444
+ }
445
+ }
446
+ return false;
447
+ }
448
+
449
+ /**
450
+ * Get directory contents in PHP array
451
+ * @param string $dir
452
+ * @param bool $recursive
453
+ * @return array
454
+ */
455
+ public function ls($dir = "/", $recursive = false)
456
+ {
457
+ $dir= $this->correctFilePath($dir);
458
+ $rawfiles = (array) $this->rawlist($dir, $recursive);
459
+ $structure = array();
460
+ $arraypointer = &$structure;
461
+ foreach ($rawfiles as $rawfile) {
462
+ if ($rawfile[0] == '/') {
463
+ $paths = array_slice(explode('/', str_replace(':', '', $rawfile)), 1);
464
+ $arraypointer = &$structure;
465
+ foreach ($paths as $path) {
466
+ foreach ($arraypointer as $i => $file) {
467
+ if ($file['name'] == $path) {
468
+ $arraypointer = &$arraypointer[ $i ]['children'];
469
+ break;
470
+ }
471
+ }
472
+ }
473
+ } elseif(!empty($rawfile)) {
474
+ $info = preg_split("/[\s]+/", $rawfile, 9);
475
+ $arraypointer[] = array(
476
+ 'name' => $info[8],
477
+ 'dir' => $info[0]{0} == 'd',
478
+ 'size' => (int) $info[4],
479
+ 'chmod' => self::chmodnum($info[0]),
480
+ 'rawdata' => $info,
481
+ 'raw' => $rawfile
482
+ );
483
+ }
484
+ }
485
+ return $structure;
486
+ }
487
+
488
+ /**
489
+ * Correct file path
490
+ * @param $str
491
+ * @return string
492
+ */
493
+ public function correctFilePath($str)
494
+ {
495
+ $str = str_replace("\\", "/", $str);
496
+ $str = preg_replace("/^.\//", "", $str);
497
+ return $str;
498
+ }
499
+
500
+ /**
501
+ * Delete file
502
+ * @param string $file
503
+ * @return bool
504
+ */
505
+ public function delete($file)
506
+ {
507
+ $this->checkConnected();
508
+ $file = $this->correctFilePath($file);
509
+ return @ftp_delete($this->_conn, $file);
510
+ }
511
+
512
+ /**
513
+ * Remove directory
514
+ * @param string $dir
515
+ * @return bool
516
+ */
517
+ public function rmdir($dir)
518
+ {
519
+ $this->checkConnected();
520
+ $dir = $this->correctFilePath($dir);
521
+ return @ftp_rmdir($this->_conn, $dir);
522
+ }
523
+ }
downloader/lib/Mage/Connect/Loader.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class for loader which using in the Rest
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Connect_Loader
35
+ {
36
+
37
+ /**
38
+ * Factory for HTTP client
39
+ * @param string/false $protocol 'curl'/'socket' or false for auto-detect
40
+ * @return Mage_HTTP_Client/Mage_Connect_Loader_Ftp
41
+ */
42
+ public static function getInstance($protocol='')
43
+ {
44
+ if ($protocol == 'ftp') {
45
+ return new Mage_Connect_Loader_Ftp();
46
+ } else {
47
+ return Mage_HTTP_Client::getInstance();
48
+ }
49
+ }
50
+
51
+ }
downloader/lib/Mage/Connect/Loader/Ftp.php ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class for ftp loader which using in the Rest
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Connect_Loader_Ftp
35
+ {
36
+
37
+ const TEMPORARY_DIR = '../var/package/tmp';
38
+
39
+ const FTP_USER = 'anonymous';
40
+
41
+ const FTP_PASS = 'test@gmail.com';
42
+
43
+ /**
44
+ * Object of Ftp
45
+ *
46
+ * @var Mage_Connect_Ftp
47
+ */
48
+ protected $_ftp = null;
49
+
50
+ /**
51
+ * User name
52
+ * @var string
53
+ */
54
+ protected $_ftpUser = '';
55
+
56
+ /**
57
+ * User password
58
+ * @var string
59
+ */
60
+ protected $_ftpPassword = '';
61
+
62
+ /**
63
+ * Response body
64
+ * @var string
65
+ */
66
+ protected $_responseBody = '';
67
+
68
+ /**
69
+ * Response status
70
+ * @var int
71
+ */
72
+ protected $_responseStatus = 0;
73
+
74
+ /**
75
+ * Constructor
76
+ */
77
+ public function __construct()
78
+ {
79
+ $this->_ftp = new Mage_Connect_Ftp();
80
+ $this->_ftpUser = self::FTP_USER;
81
+ $this->_ftpPassword = self::FTP_PASS;
82
+ }
83
+
84
+ public function getFtp()
85
+ {
86
+ return $this->_ftp;
87
+ }
88
+
89
+ /**
90
+ * Retrieve file from URI
91
+ *
92
+ * @param mixed $uri
93
+ * @return bool
94
+ */
95
+ public function get($uri)
96
+ {
97
+ $remoteFile = basename($uri);
98
+ $uri = dirname($uri);
99
+ $uri = str_replace('http://', '', $uri);
100
+ $uri = str_replace('https://', '', $uri);
101
+ $uri = str_replace('ftp://', '', $uri);
102
+ $uri = $this->_ftpUser.":".$this->_ftpPassword."@".$uri;
103
+ $this->getFtp()->connect("ftp://".$uri);
104
+ $this->getFtp()->pasv(true);
105
+ $tmpDir = self::TEMPORARY_DIR . DS;
106
+ if (!is_dir($tmpDir)) {
107
+ $tmpDir = sys_get_temp_dir();
108
+ }
109
+ if (substr($tmpDir, -1) != DS) {
110
+ $tmpDir .= DS;
111
+ }
112
+ $localFile = $tmpDir . time() . ".xml";
113
+
114
+ if ($this->getFtp()->get($localFile, $remoteFile)) {
115
+ $this->_responseBody = file_get_contents($localFile);
116
+ $this->_responseStatus = 200;
117
+ }
118
+ @unlink($localFile);
119
+ $this->getFtp()->close();
120
+ return $this;
121
+ }
122
+
123
+ /**
124
+ * Get response status code
125
+ *
126
+ * @return string
127
+ */
128
+ public function getStatus()
129
+ {
130
+ return $this->_responseStatus;
131
+ }
132
+
133
+ /**
134
+ * put your comment there...
135
+ *
136
+ * @return string
137
+ */
138
+ public function getBody()
139
+ {
140
+ return $this->_responseBody;
141
+ }
142
+
143
+ /**
144
+ * Set login credentials for ftp auth.
145
+ * @param string $ftpLogin Ftp User account name
146
+ * @param string $ftpPassword User password
147
+ * @return string
148
+ */
149
+ public function setCredentials($ftpLogin, $ftpPassword)
150
+ {
151
+ $this->_ftpUser = $ftpLogin;
152
+ $this->_ftpPassword = $ftpPassword;
153
+ }
154
+
155
+ }
downloader/lib/Mage/Connect/Package.php ADDED
@@ -0,0 +1,1499 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to work with Magento Connect packages
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Connect_Package
35
+ {
36
+
37
+ const PACKAGE_XML_DIR = 'var/package';
38
+
39
+ /**
40
+ * Contain SimpleXMLElement for composing document.
41
+ *
42
+ * @var SimpleXMLElement
43
+ */
44
+ protected $_packageXml;
45
+
46
+ /**
47
+ * Internal cache
48
+ *
49
+ * @var array
50
+ */
51
+ protected $_authors;
52
+
53
+ /**
54
+ * Internal cache
55
+ *
56
+ * @var array
57
+ */
58
+ protected $_contents;
59
+
60
+ /**
61
+ * Internal cache
62
+ *
63
+ * @var array
64
+ */
65
+ protected $_hashContents;
66
+
67
+ /**
68
+ * Internal cache
69
+ *
70
+ * @var array
71
+ */
72
+ protected $_compatible;
73
+
74
+ /**
75
+ * Internal cache
76
+ *
77
+ * @var array
78
+ */
79
+ protected $_dependencyPhpExtensions;
80
+
81
+ /**
82
+ * Internal cache
83
+ *
84
+ * @var array
85
+ */
86
+ protected $_dependencyPackages;
87
+
88
+ /**
89
+ * A helper object that can read from a package archive
90
+ *
91
+ * @var Mage_Connect_Package_Reader
92
+ */
93
+ protected $_reader;
94
+
95
+ /**
96
+ * A helper object that can create and write to a package archive
97
+ *
98
+ * @var Mage_Connect_Package_Writer
99
+ */
100
+ protected $_writer;
101
+
102
+ /**
103
+ * Validator object
104
+ *
105
+ * @var Mage_Connect_Validator
106
+ */
107
+ protected $_validator = null;
108
+
109
+ /**
110
+ * Validation errors
111
+ *
112
+ * @var array
113
+ */
114
+ protected $_validationErrors = array();
115
+
116
+ /**
117
+ * Object with target
118
+ *
119
+ * @var Mage_Connect_Package_Target
120
+ */
121
+ protected $_target = null;
122
+
123
+ /**
124
+ * Config object
125
+ *
126
+ * @var Mage_Connect_Config
127
+ */
128
+ protected $_config = null;
129
+
130
+ /**
131
+ * Creates a package object (empty, or from existing archive, or from package definition xml)
132
+ *
133
+ * @param null|string|resource $source
134
+ */
135
+ public function __construct($source=null)
136
+ {
137
+ libxml_use_internal_errors(true);
138
+
139
+ if (is_string($source)) {
140
+ // check what's in the string (a package definition or a package filename)
141
+ if (0 === strpos($source, "<?xml")) {
142
+ // package definition xml
143
+ $this->_init($source);
144
+ } elseif (is_file($source) && is_readable($source)) {
145
+ // package archive filename
146
+ $this->_loadFile($source);
147
+ } else {
148
+ throw new Mage_Exception('Invalid package source');
149
+ }
150
+ } elseif (is_resource($source)) {
151
+ $this->_loadResource($source);
152
+ } elseif (is_null($source)) {
153
+ $this->_init();
154
+ } else {
155
+ throw new Mage_Exception('Invalid package source');
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Initializes an empty package object
161
+ *
162
+ * @param null|string $definition optional package definition xml
163
+ * @return Mage_Connect_Package
164
+ */
165
+ protected function _init($definition=null)
166
+ {
167
+
168
+ if (!is_null($definition)) {
169
+ $this->_packageXml = simplexml_load_string($definition);
170
+ } else {
171
+ $packageXmlStub = <<<END
172
+ <?xml version="1.0"?>
173
+ <package>
174
+ <name />
175
+ <version />
176
+ <stability />
177
+ <license />
178
+ <channel />
179
+ <extends />
180
+ <summary />
181
+ <description />
182
+ <notes />
183
+ <authors />
184
+ <date />
185
+ <time />
186
+ <contents />
187
+ <compatible />
188
+ <dependencies />
189
+ </package>
190
+ END;
191
+ $this->_packageXml = simplexml_load_string($packageXmlStub);
192
+ }
193
+ return $this;
194
+ }
195
+
196
+ /**
197
+ * Loads a package from specified file
198
+ *
199
+ * @param string $filename
200
+ * @return Mage_Connect_Package
201
+ */
202
+ protected function _loadFile($filename='')
203
+ {
204
+ if (is_null($this->_reader)) {
205
+ $this->_reader = new Mage_Connect_Package_Reader($filename);
206
+ }
207
+ $content = $this->_reader->load();
208
+ $this->_packageXml = simplexml_load_string($content);
209
+ return $this;
210
+ }
211
+
212
+ /**
213
+ * Creates a package and saves it
214
+ *
215
+ * @param string $path
216
+ * @return Mage_Connect_Package
217
+ */
218
+ public function save($path)
219
+ {
220
+ $this->validate();
221
+ $path = rtrim($path, "\\/") . DS;
222
+ $this->_savePackage($path);
223
+ return $this;
224
+ }
225
+
226
+ /**
227
+ * Creates a package archive and saves it to specified path
228
+ *
229
+ * @param string $path
230
+ * @return Mage_Connect_Package
231
+ */
232
+ protected function _savePackage($path)
233
+ {
234
+ $fileName = $this->getReleaseFilename();
235
+ if (is_null($this->_writer)) {
236
+ $this->_writer = new Mage_Connect_Package_Writer($this->getContents(), $path.$fileName);
237
+ }
238
+ $this->_writer
239
+ ->composePackage()
240
+ ->addPackageXml($this->getPackageXml())
241
+ ->archivePackage();
242
+ return $this;
243
+ }
244
+
245
+ /**
246
+ * Retrieve Target object
247
+ *
248
+ * @return Mage_Connect_Package_Target
249
+ */
250
+ protected function getTarget()
251
+ {
252
+ if (!$this->_target instanceof Mage_Connect_Package_Target) {
253
+ $this->_target = new Mage_Connect_Package_Target();
254
+ }
255
+ return $this->_target;
256
+ }
257
+
258
+ public function setTarget($arg)
259
+ {
260
+ if ($arg instanceof Mage_Connect_Package_Target) {
261
+ $this->_target = $arg;
262
+ }
263
+ }
264
+
265
+ /* Mutators */
266
+
267
+ /**
268
+ * Puts value to name
269
+ *
270
+ * @param string $name
271
+ * @return Mage_Connect_Package
272
+ */
273
+ public function setName($name)
274
+ {
275
+ $this->_packageXml->name = $name;
276
+ return $this;
277
+ }
278
+
279
+ /**
280
+ * Puts value to <channel />
281
+ *
282
+ * @param string $channel
283
+ * @return Mage_Connect_Package
284
+ */
285
+ public function setChannel($channel)
286
+ {
287
+ $this->_packageXml->channel = $channel;
288
+ return $this;
289
+ }
290
+
291
+ /**
292
+ * Puts value to <summary />
293
+ *
294
+ * @param string $summary
295
+ * @return Mage_Connect_Package
296
+ */
297
+ public function setSummary($summary)
298
+ {
299
+ $this->_packageXml->summary = $summary;
300
+ return $this;
301
+ }
302
+
303
+ /**
304
+ * Puts value to <description />
305
+ *
306
+ * @param string $description
307
+ * @return Mage_Connect_Package
308
+ */
309
+ public function setDescription($description)
310
+ {
311
+ $this->_packageXml->description = $description;
312
+ return $this;
313
+ }
314
+
315
+ /**
316
+ * Puts value to <authors />
317
+ *
318
+ * array(
319
+ * array('name'=>'Name1', 'user'=>'User1', 'email'=>'email1@email.com'),
320
+ * array('name'=>'Name2', 'user'=>'User2', 'email'=>'email2@email.com'),
321
+ * );
322
+ *
323
+ * @param array $authors
324
+ * @return Mage_Connect_Package
325
+ */
326
+ public function setAuthors($authors)
327
+ {
328
+ $this->_authors = $authors;
329
+ foreach ($authors as $_author) {
330
+ $this->addAuthor($_author['name'], $_author['user'], $_author['email']);
331
+ }
332
+ return $this;
333
+ }
334
+
335
+ /**
336
+ * Add author to <authors/>
337
+ *
338
+ * @param string $name
339
+ * @param string $user
340
+ * @param string $email
341
+ * @return Mage_Connect_Package
342
+ */
343
+ public function addAuthor($name=null, $user=null, $email=null)
344
+ {
345
+ $this->_authors[] = array(
346
+ 'name' =>$name,
347
+ 'user' =>$user,
348
+ 'email'=>$email
349
+ );
350
+ $author = $this->_packageXml->authors->addChild('author');
351
+ $author->addChild('name', $name);
352
+ $author->addChild('user', $user);
353
+ $author->addChild('email', $email);
354
+ return $this;
355
+ }
356
+
357
+ /**
358
+ * Puts value to <date/>. Format should be Y-M-D.
359
+ *
360
+ * @param string $date
361
+ * @return Mage_Connect_Package
362
+ */
363
+ public function setDate($date)
364
+ {
365
+ $this->_packageXml->date = $date;
366
+ return $this;
367
+ }
368
+
369
+ /**
370
+ * Puts value to <time />. Format should be H:i:s.
371
+ *
372
+ * @param string $time
373
+ * @return Mage_Connect_Package
374
+ */
375
+ public function setTime($time)
376
+ {
377
+ $this->_packageXml->time = $time;
378
+ return $this;
379
+ }
380
+
381
+ /**
382
+ * Puts value to <version/>. Format should be X.Y.Z.
383
+ *
384
+ * @param string $version
385
+ * @return Mage_Connect_Package
386
+ */
387
+ public function setVersion($version)
388
+ {
389
+ $this->_packageXml->version = $version;
390
+ return $this;
391
+ }
392
+
393
+ /**
394
+ * Puts value to <stability/>. It can be alpha, beta, devel and stable.
395
+ *
396
+ * @param string $stability
397
+ * @return Mage_Connect_Package
398
+ */
399
+ public function setStability($stability)
400
+ {
401
+ $this->_packageXml->stability = $stability;
402
+ return $this;
403
+ }
404
+
405
+ /**
406
+ * Puts value to <license/>, also method can used for set attribute URI.
407
+ *
408
+ * @param string $license
409
+ * @param string $uri
410
+ * @return Mage_Connect_Package
411
+ */
412
+ public function setLicense($license, $uri=null)
413
+ {
414
+ $this->_packageXml->license = $license;
415
+ if ($uri) {
416
+ $this->_packageXml->license['uri'] = $uri;
417
+ }
418
+ return $this;
419
+ }
420
+
421
+ /**
422
+ * Puts value to <notes/>.
423
+ *
424
+ * @param string $notes
425
+ * @return Mage_Connect_Package
426
+ */
427
+ public function setNotes($notes)
428
+ {
429
+ $this->_packageXml->notes = $notes;
430
+ return $this;
431
+ }
432
+
433
+ /**
434
+ * Retrieve SimpleXMLElement node by xpath. If it absent, create new.
435
+ * For comparing nodes method uses attribute "name" in each nodes.
436
+ * If attribute "name" is same for both nodes, nodes are same.
437
+ *
438
+ * @param string $tag
439
+ * @param SimpleXMLElement $parent
440
+ * @param string $name
441
+ * @return SimpleXMLElement
442
+ */
443
+ protected function _getNode($tag, $parent, $name='')
444
+ {
445
+ $found = false;
446
+ foreach ($parent->xpath($tag) as $_node) {
447
+ if ($_node['name'] == $name) {
448
+ $node = $_node;
449
+ $found = true;
450
+ break;
451
+ }
452
+ }
453
+ if (!$found) {
454
+ $node = $parent->addChild($tag);
455
+ if ($name) {
456
+ $node->addAttribute('name', $name);
457
+ }
458
+ }
459
+ return $node;
460
+ }
461
+
462
+ /**
463
+ * Add directory or file to <contents />.
464
+ *
465
+ * @param string $path Path to directory or file
466
+ * @param string $targetName Target name.
467
+ * @param string $hash MD5 hash of the file
468
+ * @return Mage_Connect_Package
469
+ */
470
+ public function addContent($path, $targetName)
471
+ {
472
+ $found = false;
473
+ $parent = $this->_getNode('target', $this->_packageXml->contents, $targetName);
474
+ $source = str_replace('\\', '/', $path);
475
+ $directories = explode('/', dirname($source));
476
+ foreach ($directories as $directory) {
477
+ $parent = $this->_getNode('dir', $parent, $directory);
478
+ }
479
+ $fileName = basename($source);
480
+ if ($fileName!='') {
481
+ $fileNode = $parent->addChild('file');
482
+ $fileNode->addAttribute('name', $fileName);
483
+ $targetDir = $this->getTarget()->getTargetUri($targetName);
484
+ $hash = md5_file($targetDir.DS.$path);
485
+ $fileNode->addAttribute('hash', $hash);
486
+ }
487
+ return $this;
488
+ }
489
+
490
+ /**
491
+ * Add directory recursively (with subdirectory and file).
492
+ * Exclude and Include can be add using Regular Expression.
493
+ *
494
+ * @param string $targetName Target name
495
+ * @param string $targetDir Path for target name
496
+ * @param string $path Path to directory
497
+ * @param string $exclude Exclude
498
+ * @param string $include Include
499
+ * @return Mage_Connect_Package
500
+ */
501
+ public function addContentDir($targetName, $path, $exclude=null, $include=null)
502
+ {
503
+ $targetDir = $this->getTarget()->getTargetUri($targetName);
504
+ $targetDirLen = strlen($targetDir . DS);
505
+ //get all subdirectories and files.
506
+ $entries = @glob($targetDir. DS . $path . DS . "{,.}*", GLOB_BRACE);
507
+ if (!empty($entries)) {
508
+ foreach ($entries as $entry) {
509
+ $filePath = substr($entry, $targetDirLen);
510
+ if (!empty($include) && !preg_match($include, $filePath)) {
511
+ continue;
512
+ }
513
+ if (!empty($exclude) && preg_match($exclude, $filePath)) {
514
+ continue;
515
+ }
516
+ if (is_dir($entry)) {
517
+ $baseName = basename($entry);
518
+ if ('.'===$baseName || '..'===$baseName) {
519
+ continue;
520
+ }
521
+ //for subdirectory call method recursively
522
+ $this->addContentDir($targetName, $filePath, $exclude, $include);
523
+ } elseif (is_file($entry)) {
524
+ $this->addContent($filePath, $targetName);
525
+ }
526
+ }
527
+ }
528
+ return $this;
529
+ }
530
+
531
+ /**
532
+ * Add value to <compatible />.
533
+ *
534
+ * @param string $packageName
535
+ * @param string $channel
536
+ * @param string $minVersion
537
+ * @param string $maxVersion
538
+ * @return Mage_Connect_Package
539
+ */
540
+ public function addCompatible($packageName, $channel, $minVersion, $maxVersion)
541
+ {
542
+ $package = $this->_packageXml->compatible->addChild('package');
543
+ $package->addChild('name', $packageName);
544
+ $package->addChild('channel', $channel);
545
+ $package->addChild('min', $minVersion);
546
+ $package->addChild('max', $maxVersion);
547
+ return $this;
548
+ }
549
+
550
+ /**
551
+ * Set dependency from php version.
552
+ *
553
+ * @param string $minVersion
554
+ * @param string $maxVersion
555
+ * @return Mage_Connect_Package
556
+ */
557
+ public function setDependencyPhpVersion($minVersion, $maxVersion)
558
+ {
559
+ $parent = $this->_packageXml->dependencies;
560
+ $parent = $this->_getNode('required', $parent);
561
+ $parent = $this->_getNode('php', $parent);
562
+ $parent->addChild('min', $minVersion);
563
+ $parent->addChild('max', $maxVersion);
564
+ return $this;
565
+ }
566
+
567
+
568
+ /**
569
+ * Check PHP version restriction
570
+ * @param $phpVersion PHP_VERSION by default
571
+ * @return true | string
572
+ */
573
+ public function checkPhpVersion()
574
+ {
575
+ $min = $this->getDependencyPhpVersionMin();
576
+ $max = $this->getDependencyPhpVersionMax();
577
+
578
+ $minOk = $min? version_compare(PHP_VERSION, $min, ">=") : true;
579
+ $maxOk = $max? version_compare(PHP_VERSION, $max, "<=") : true;
580
+
581
+ if(!$minOk || !$maxOk) {
582
+ $err = "requires PHP version ";
583
+ if($min && $max) {
584
+ $err .= " >= $min and <= $max ";
585
+ } elseif($min) {
586
+ $err .= " >= $min ";
587
+ } elseif($max) {
588
+ $err .= " <= $max ";
589
+ }
590
+ $err .= " current is: ".PHP_VERSION;
591
+ return $err;
592
+ }
593
+ return true;
594
+ }
595
+
596
+
597
+ /**
598
+ * Check PHP extensions availability
599
+ * @throws Exceptiom on failure
600
+ * @return true | array
601
+ */
602
+ public function checkPhpDependencies()
603
+ {
604
+ $errors = array();
605
+ foreach($this->getDependencyPhpExtensions() as $dep)
606
+ {
607
+ if(!extension_loaded($dep['name'])) {
608
+ $errors[] = $dep;
609
+ }
610
+ }
611
+ if(count($errors)) {
612
+ return $errors;
613
+ }
614
+ return true;
615
+ }
616
+
617
+
618
+ /**
619
+ * Set dependency from php extensions.
620
+ *
621
+ * $extension has next view:
622
+ * array('curl', 'mysql')
623
+ *
624
+ * @param array|string $extensions
625
+ * @return Mage_Connect_Package
626
+ */
627
+ public function setDependencyPhpExtensions($extensions)
628
+ {
629
+ foreach($extensions as $_extension) {
630
+ $this->addDependencyExtension(
631
+ $_extension['name'],
632
+ $_extension['min_version'],
633
+ $_extension['max_version']
634
+ );
635
+ }
636
+ return $this;
637
+ }
638
+
639
+ /**
640
+ * Set dependency from another packages.
641
+ *
642
+ * $packages should contain:
643
+ * array(
644
+ * array('name'=>'test1', 'channel'=>'test1', 'min_version'=>'0.0.1', 'max_version'=>'0.1.0'),
645
+ * array('name'=>'test2', 'channel'=>'test2', 'min_version'=>'0.0.1', 'max_version'=>'0.1.0'),
646
+ * )
647
+ *
648
+ * @param array $packages
649
+ * @param bool $clear
650
+ * @return Mage_Connect_Package
651
+ */
652
+ public function setDependencyPackages($packages, $clear = false)
653
+ {
654
+ if($clear) {
655
+ unset($this->_packageXml->dependencies->required->package);
656
+ }
657
+
658
+ foreach($packages as $_package) {
659
+
660
+ $filesArrayCondition = isset($_package['files']) && is_array($_package['files']);
661
+ $filesArray = $filesArrayCondition ? $_package['files'] : array();
662
+
663
+ $this->addDependencyPackage(
664
+ $_package['name'],
665
+ $_package['channel'],
666
+ $_package['min_version'],
667
+ $_package['max_version'],
668
+ $filesArray
669
+ );
670
+ }
671
+ return $this;
672
+ }
673
+
674
+
675
+
676
+ /**
677
+ * Add package to dependency packages.
678
+ *
679
+ * @param string $package
680
+ * @param string $channel
681
+ * @param string $minVersion
682
+ * @param string $maxVersion
683
+ * @return Mage_Connect_Package
684
+ */
685
+ public function addDependencyPackage($name, $channel, $minVersion, $maxVersion, $files = array())
686
+ {
687
+ $parent = $this->_packageXml->dependencies;
688
+ $parent = $this->_getNode('required', $parent);
689
+ $parent = $parent->addChild('package');
690
+ $parent->addChild('name', $name);
691
+ $parent->addChild('channel', $channel);
692
+ $parent->addChild('min', $minVersion);
693
+ $parent->addChild('max', $maxVersion);
694
+ if(count($files)) {
695
+ $parent = $parent->addChild('files');
696
+ foreach($files as $row) {
697
+ if(!empty($row['target']) && !empty($row['path'])) {
698
+ $node = $parent->addChild("file");
699
+ $node["target"] = $row['target'];
700
+ $node["path"] = $row['path'];
701
+
702
+ }
703
+ }
704
+ }
705
+ return $this;
706
+ }
707
+
708
+
709
+
710
+ /**
711
+ * Add package to dependency extension.
712
+ *
713
+ * @param string $package
714
+ * @param string $minVersion
715
+ * @param string $maxVersion
716
+ * @return Mage_Connect_Package
717
+ */
718
+ public function addDependencyExtension($name, $minVersion, $maxVersion)
719
+ {
720
+ $parent = $this->_packageXml->dependencies;
721
+ $parent = $this->_getNode('required', $parent);
722
+ $parent = $parent->addChild('extension');
723
+ $parent->addChild('name', $name);
724
+ $parent->addChild('min', $minVersion);
725
+ $parent->addChild('max', $maxVersion);
726
+ return $this;
727
+ }
728
+
729
+ /* Accessors */
730
+
731
+ /**
732
+ * Getter
733
+ *
734
+ * @return string
735
+ */
736
+ public function getName()
737
+ {
738
+ return (string)$this->_packageXml->name;
739
+ }
740
+
741
+ /**
742
+ * Getter
743
+ *
744
+ * @return string
745
+ */
746
+ public function getChannel()
747
+ {
748
+ return (string)$this->_packageXml->channel;
749
+ }
750
+
751
+ /**
752
+ * Getter
753
+ *
754
+ * @return string
755
+ */
756
+ public function getSummary()
757
+ {
758
+ return (string)$this->_packageXml->summary;
759
+ }
760
+
761
+ /**
762
+ * Getter
763
+ *
764
+ * @return string
765
+ */
766
+ public function getDescription()
767
+ {
768
+ return (string)$this->_packageXml->description;
769
+ }
770
+
771
+ /**
772
+ * Get list of authors in associative array.
773
+ *
774
+ * @return array
775
+ */
776
+ public function getAuthors()
777
+ {
778
+ if (is_array($this->_authors)) return $this->_authors;
779
+ $this->_authors = array();
780
+ if(!isset($this->_packageXml->authors->author)) {
781
+ return array();
782
+ }
783
+ foreach ($this->_packageXml->authors->author as $_author) {
784
+ $this->_authors[] = array(
785
+ 'name' => (string)$_author->name,
786
+ 'user' => (string)$_author->user,
787
+ 'email'=> (string)$_author->email
788
+ );
789
+ }
790
+ return $this->_authors;
791
+ }
792
+
793
+ /**
794
+ * Getter
795
+ *
796
+ * @return string
797
+ */
798
+ public function getDate()
799
+ {
800
+ return (string)$this->_packageXml->date;
801
+ }
802
+
803
+ /**
804
+ * Getter
805
+ *
806
+ * @return string
807
+ */
808
+ public function getTime()
809
+ {
810
+ return (string)$this->_packageXml->time;
811
+ }
812
+
813
+ /**
814
+ * Getter
815
+ *
816
+ * @return string
817
+ */
818
+ public function getVersion()
819
+ {
820
+ return (string)$this->_packageXml->version;
821
+ }
822
+
823
+ /**
824
+ * Getter
825
+ *
826
+ * @return string
827
+ */
828
+ public function getStability()
829
+ {
830
+ return (string)$this->_packageXml->stability;
831
+ }
832
+
833
+ /**
834
+ * Getter
835
+ *
836
+ * @return string
837
+ */
838
+ public function getLicense()
839
+ {
840
+ return (string)$this->_packageXml->license;
841
+ }
842
+
843
+ /**
844
+ * Getter
845
+ *
846
+ * @return string
847
+ */
848
+ public function getLicenseUri()
849
+ {
850
+ return (string)$this->_packageXml->license['uri'];
851
+ }
852
+
853
+ /**
854
+ * Getter
855
+ *
856
+ * @return string
857
+ */
858
+ public function getNotes()
859
+ {
860
+ return (string)$this->_packageXml->notes;
861
+ }
862
+
863
+ /**
864
+ * Create list of all files from package.xml
865
+ *
866
+ * @return array
867
+ */
868
+ public function getContents()
869
+ {
870
+ if (is_array($this->_contents)) return $this->_contents;
871
+ $this->_contents = array();
872
+ if(!isset($this->_packageXml->contents->target)) {
873
+ return $this->_contents;
874
+ }
875
+ foreach($this->_packageXml->contents->target as $target) {
876
+ $targetUri = $this->getTarget()->getTargetUri($target['name']);
877
+ $this->_getList($target, $targetUri);
878
+ }
879
+ return $this->_contents;
880
+ }
881
+
882
+ /**
883
+ * Helper for getContents(). Create recursively list.
884
+ *
885
+ * @param SimpleXMLElement $parent
886
+ * @param string $path
887
+ */
888
+ protected function _getList($parent, $path)
889
+ {
890
+ if (count($parent) == 0) {
891
+ $this->_contents[] = $path;
892
+ } else {
893
+ foreach($parent as $_content) {
894
+ $this->_getList($_content, ($path ? $path . DS : '') . $_content['name']);
895
+ }
896
+ }
897
+ }
898
+
899
+ /**
900
+ * Create list of all files from package.xml with hash
901
+ *
902
+ * @return array
903
+ */
904
+ public function getHashContents()
905
+ {
906
+ if (is_array($this->_hashContents)) return $this->_hashContents;
907
+ $this->_hashContents = array();
908
+ if(!isset($this->_packageXml->contents->target)) {
909
+ return $this->_hashContents;
910
+ }
911
+ foreach($this->_packageXml->contents->target as $target) {
912
+ $targetUri = $this->getTarget()->getTargetUri($target['name']);
913
+ $this->_getHashList($target, $targetUri);
914
+ }
915
+ return $this->_hashContents;
916
+ }
917
+
918
+ /**
919
+ * Helper for getHashContents(). Create recursively list.
920
+ *
921
+ * @param SimpleXMLElement $parent
922
+ * @param string $path
923
+ */
924
+ protected function _getHashList($parent, $path, $hash='')
925
+ {
926
+ if (count($parent) == 0) {
927
+ $this->_hashContents[$path] = $hash;
928
+ } else {
929
+ foreach($parent as $_content) {
930
+ $contentHash = '';
931
+ if (isset($_content['hash'])) {
932
+ $contentHash = (string)$_content['hash'];
933
+ }
934
+ $this->_getHashList($_content, ($path ? $path . DS : '') . $_content['name'], $contentHash);
935
+ }
936
+ }
937
+ }
938
+
939
+ /**
940
+ * Get compatible packages.
941
+ *
942
+ * @return array
943
+ */
944
+ public function getCompatible()
945
+ {
946
+ if (is_array($this->_compatible)) return $this->_compatible;
947
+ $this->_compatible = array();
948
+ if(!isset($this->_packageXml->compatible->package)) {
949
+ return array();
950
+ }
951
+ foreach ($this->_packageXml->compatible->package as $_package) {
952
+ $this->_compatible[] = array(
953
+ 'name' => (string)$_package->name,
954
+ 'channel' => (string)$_package->channel,
955
+ 'min' => (string)$_package->min,
956
+ 'max' => (string)$_package->max
957
+ );
958
+ }
959
+ return $this->_compatible;
960
+ }
961
+
962
+ /**
963
+ * Getter
964
+ *
965
+ * @return string
966
+ */
967
+ public function getDependencyPhpVersionMin()
968
+ {
969
+ if(!isset($this->_packageXml->dependencies->required->php->min)) {
970
+ return false;
971
+ }
972
+ return (string)$this->_packageXml->dependencies->required->php->min;
973
+ }
974
+
975
+ /**
976
+ * Getter
977
+ *
978
+ * @return string
979
+ */
980
+ public function getDependencyPhpVersionMax()
981
+ {
982
+ if(!isset($this->_packageXml->dependencies->required->php->max)) {
983
+ return false;
984
+ }
985
+ return (string)$this->_packageXml->dependencies->required->php->max;
986
+ }
987
+
988
+ /**
989
+ * Get list of php extensions.
990
+ *
991
+ * @return array
992
+ */
993
+ public function getDependencyPhpExtensions()
994
+ {
995
+ if (is_array($this->_dependencyPhpExtensions)) return $this->_dependencyPhpExtensions;
996
+ $this->_dependencyPhpExtensions = array();
997
+ if (!isset($this->_packageXml->dependencies->required->extension)) {
998
+ return $this->_dependencyPhpExtensions;
999
+ }
1000
+ foreach($this->_packageXml->dependencies->required->extension as $_package) {
1001
+ $this->_dependencyPhpExtensions[] = array(
1002
+ 'name' => (string)$_package->name,
1003
+ 'min' => (string)$_package->min,
1004
+ 'max' => (string)$_package->max,
1005
+ );
1006
+ }
1007
+ return $this->_dependencyPhpExtensions;
1008
+ }
1009
+
1010
+ /**
1011
+ * Get list of dependency packages.
1012
+ *
1013
+ * @return array
1014
+ */
1015
+ public function getDependencyPackages()
1016
+ {
1017
+ $this->_dependencyPackages = array();
1018
+ if (!isset($this->_packageXml->dependencies->required->package)) {
1019
+ return $this->_dependencyPackages;
1020
+ }
1021
+ foreach($this->_packageXml->dependencies->required->package as $_package) {
1022
+ $add = array(
1023
+ 'name' => (string)$_package->name,
1024
+ 'channel' => (string)$_package->channel,
1025
+ 'min' => (string)$_package->min,
1026
+ 'max' => (string)$_package->max,
1027
+ );
1028
+ if(isset($_package->files)) {
1029
+ $add['files'] = array();
1030
+ foreach($_package->files as $node) {
1031
+ if(isset($node->file)) {
1032
+
1033
+ $add['files'][] = array('target' => (string) $node->file['target'], 'path'=> (string) $node->file['path']);
1034
+ }
1035
+ }
1036
+ }
1037
+ $this->_dependencyPackages[] = $add;
1038
+ }
1039
+ return $this->_dependencyPackages;
1040
+ }
1041
+
1042
+
1043
+
1044
+
1045
+ /**
1046
+ * Get string with XML content.
1047
+ *
1048
+ * @return string
1049
+ */
1050
+ public function getPackageXml()
1051
+ {
1052
+ return $this->_packageXml->asXml();
1053
+ }
1054
+
1055
+
1056
+ /**
1057
+ * Validator instance (single)
1058
+ *
1059
+ * @return Mage_Connect_Validator
1060
+ */
1061
+ protected function validator()
1062
+ {
1063
+ if(is_null($this->_validator)) {
1064
+ $this->_validator = new Mage_Connect_Validator();
1065
+ }
1066
+ return $this->_validator;
1067
+ }
1068
+
1069
+ /**
1070
+ * Get validation error strings
1071
+ *
1072
+ * @return array
1073
+ */
1074
+ public function getErrors()
1075
+ {
1076
+ return $this->_validationErrors;
1077
+ }
1078
+
1079
+ /**
1080
+ * Setter for validation errors
1081
+ *
1082
+ * @param array $errors
1083
+ * @return
1084
+ */
1085
+ protected function setErrors(array $errors)
1086
+ {
1087
+ $this->_validationErrors = $errors;
1088
+ }
1089
+
1090
+ /**
1091
+ * Check validation result.
1092
+ * Returns true if package data is invalid.
1093
+ *
1094
+ * @return bool
1095
+ */
1096
+ public function hasErrors()
1097
+ {
1098
+ return count($this->_validationErrors) != 0;
1099
+ }
1100
+
1101
+ /**
1102
+ * Validate package. Errors can be
1103
+ * retreived by calling getErrors();
1104
+ *
1105
+ * @return bool
1106
+ */
1107
+ public function validate()
1108
+ {
1109
+ $v = $this->validator();
1110
+
1111
+ /**
1112
+ * Validation map
1113
+ *
1114
+ * Format:
1115
+ *
1116
+ * 'key' => array(
1117
+ * 'method' => this class method name to call, string, required
1118
+ * 'method_args' => optional args for 'method' call, array, optional
1119
+ * 'v_method' => validator method to call, string, required
1120
+ * 'error' => custom error string when validation fails, optional
1121
+ * if not set, error string fprmatted as "Invalid '$key' specified"
1122
+ * 'v_error_method' => validator method - when called returned error string
1123
+ * prepared by validator, optional,
1124
+ * if not set => see 'error'
1125
+ * 'optional' => optional value, if it's empty validation result ignored
1126
+ *
1127
+ */
1128
+ $validateMap = array(
1129
+ 'name' => array('method' => 'getName',
1130
+ 'v_method' => 'validatePackageName',
1131
+ 'error'=>"Invalid package name, allowed: [a-zA-Z0-9_-] chars"),
1132
+ 'version' => array('method' => 'getVersion',
1133
+ 'v_method' => 'validateVersion',
1134
+ 'error'=>"Invalid version, should be like: x.x.x"),
1135
+ 'stability' => array('method' => 'getStability',
1136
+ 'v_method' => 'validateStability',
1137
+ 'error'=>"Invalid stability"),
1138
+ 'date' => array('method' => 'getDate',
1139
+ 'v_method' => 'validateDate',
1140
+ 'error'=>"Invalid date, should be YYYY-DD-MM"),
1141
+ 'license_uri' => array('method' => 'getLicenseUri',
1142
+ 'v_method' => 'validateLicenseUrl',
1143
+ 'error'=>"Invalid license URL"),
1144
+ 'channel' => array('method' => 'getChannel',
1145
+ 'v_method' => 'validateChannelNameOrUri',
1146
+ 'error'=>"Invalid channel URL"),
1147
+ 'authors' => array('method' => 'getAuthors',
1148
+ 'v_method' => 'validateAuthors',
1149
+ 'v_error_method' => 'getErrors'),
1150
+ 'php_min' => array('method' => 'getDependencyPhpVersionMin',
1151
+ 'v_method' => 'validateVersion',
1152
+ 'error' => 'PHP minimum version invalid',
1153
+ 'optional' => true ),
1154
+ 'php_max' => array('method' => 'getDependencyPhpVersionMax',
1155
+ 'v_method' => 'validateVersion',
1156
+ 'error' => 'PHP maximum version invalid',
1157
+ 'optional' => true ),
1158
+ 'compatible' => array('method' => 'getCompatible',
1159
+ 'v_method' => 'validateCompatible',
1160
+ 'v_error_method' => 'getErrors'),
1161
+ 'content' => array('method' => 'getContents',
1162
+ 'v_method' => 'validateContents',
1163
+ 'v_args' => array('config' => $this->getConfig()),
1164
+ 'v_error_method' => 'getErrors'),
1165
+ );
1166
+
1167
+ $errors = array();
1168
+ /**
1169
+ * Iterate validation map
1170
+ */
1171
+ foreach($validateMap as $name=>$data) {
1172
+
1173
+ /**
1174
+ * Check mandatory rules fields
1175
+ */
1176
+ if(!isset($data['method'], $data['v_method'])) {
1177
+ throw new Mage_Exception("Invalid rules specified!");
1178
+ }
1179
+
1180
+ $method = $data['method'];
1181
+ $validatorMethod = $data['v_method'];
1182
+
1183
+ /**
1184
+ * If $optional === false, value is mandatory
1185
+ */
1186
+ $optional = isset($data['optional']) ? (bool) $data['optional'] : false;
1187
+
1188
+ /**
1189
+ * Check for method availability, package
1190
+ */
1191
+ if(!method_exists($this, $method)) {
1192
+ throw new Mage_Exception("Invalid method specified for Package : $method");
1193
+ }
1194
+
1195
+ /**
1196
+ * Check for method availability, validator
1197
+ */
1198
+ if(!method_exists($v, $validatorMethod)) {
1199
+ throw new Mage_Exception("Invalid method specified for Validator : $validatorMethod");
1200
+ }
1201
+
1202
+ /**
1203
+ * If $data['error'] => get error string from $data['error']
1204
+ * Else concatenate "Invalid '{$name}' specified"
1205
+ */
1206
+ $errorString = isset($data['error']) ? $data['error'] : "Invalid '{$name}' specified";
1207
+
1208
+ /**
1209
+ * Additional method args check
1210
+ * array() by default
1211
+ */
1212
+ $methodArgs = isset($data['method_args']) ? $data['method_args'] : array();
1213
+
1214
+ /**
1215
+ * Call package method
1216
+ */
1217
+ $out = @call_user_func_array(array($this, $method), $methodArgs);
1218
+
1219
+ /**
1220
+ * Skip if result is empty and value is optional
1221
+ */
1222
+ if(empty($out) && $optional) {
1223
+ continue;
1224
+ }
1225
+
1226
+ /**
1227
+ * Additional validator arguments, merged with array($out)
1228
+ */
1229
+ $validatorArgs = isset($data['v_args']) ? array_merge(array($out), $data['v_args']) : array($out);
1230
+
1231
+ /**
1232
+ * Get validation result
1233
+ */
1234
+ $result = call_user_func_array(array($v, $validatorMethod), $validatorArgs);
1235
+
1236
+ /**
1237
+ * Skip if validation success
1238
+ */
1239
+ if($result) {
1240
+ continue;
1241
+ }
1242
+
1243
+ /**
1244
+ * From where to get error string?
1245
+ * If validator callback method specified, call it to get errors array
1246
+ * Else get it from $errorString - local error string
1247
+ */
1248
+ $validatorFetchErrorsMethod = isset($data['v_error_method']) ? $data['v_error_method'] : false;
1249
+ if (false !== $validatorFetchErrorsMethod) {
1250
+ $errorString = call_user_func_array(array($v, $validatorFetchErrorsMethod), array());
1251
+ }
1252
+
1253
+ /**
1254
+ * If errors is array => merge
1255
+ * Else append
1256
+ */
1257
+ if(is_array($errorString)) {
1258
+ $errors = array_merge($errors, $errorString);
1259
+ } else {
1260
+ $errors[] = $errorString;
1261
+ }
1262
+ }
1263
+ /**
1264
+ * Set local errors
1265
+ */
1266
+ $this->setErrors($errors);
1267
+ /**
1268
+ * Return true if there's no errors :)
1269
+ */
1270
+ return ! $this->hasErrors();
1271
+ }
1272
+
1273
+ /**
1274
+ * Return package release filename w/o extension
1275
+ * @return string
1276
+ */
1277
+ public function getReleaseFilename()
1278
+ {
1279
+ return $this->getName()."-".$this->getVersion();
1280
+ }
1281
+
1282
+ /**
1283
+ * Return release filepath w/o extension
1284
+ * @return string
1285
+ */
1286
+ public function getRelaseDirFilename()
1287
+ {
1288
+ return $this->getName() . DS . $this->getVersion() . DS . $this->getReleaseFilename();
1289
+ }
1290
+
1291
+ /**
1292
+ * Clear dependencies
1293
+ *
1294
+ * @return Mage_Connect_Package
1295
+ */
1296
+ public function clearDependencies()
1297
+ {
1298
+ $this->_packageXml->dependencies = null;
1299
+ return $this;
1300
+ }
1301
+
1302
+ /**
1303
+ * Clear contents
1304
+ *
1305
+ * @return Mage_Connect_Package
1306
+ */
1307
+ public function clearContents()
1308
+ {
1309
+ $this->_packageXml->contents = null;
1310
+ return $this;
1311
+ }
1312
+
1313
+ /**
1314
+ * Get config
1315
+ *
1316
+ * @return Mage_Connect_Config
1317
+ */
1318
+ public function getConfig()
1319
+ {
1320
+ return $this->_config;
1321
+ }
1322
+
1323
+ /**
1324
+ * Set config
1325
+ *
1326
+ * @param Mage_Connect_Config $config
1327
+ */
1328
+ public function setConfig($config)
1329
+ {
1330
+ $this->_config = $config;
1331
+ }
1332
+
1333
+ /**
1334
+ * Import package information from previous version of Magento Connect Manager
1335
+ *
1336
+ * @param array $data
1337
+ *
1338
+ * @return Mage_Connect_Package
1339
+ */
1340
+ public function importDataV1x(array $data)
1341
+ {
1342
+ $this->_packageXml = null;
1343
+ $this->_init();
1344
+ // Import simple data
1345
+ if (isset($data['name'])) {
1346
+ $this->setName($data['name']);
1347
+ }
1348
+ if (isset($data['summary'])) {
1349
+ $this->setSummary($data['summary']);
1350
+ }
1351
+ if (isset($data['description'])) {
1352
+ $this->setDescription($data['description']);
1353
+ }
1354
+ if (isset($data['channel'])) {
1355
+ $this->setChannel($this->convertChannelFromV1x($data['channel']));
1356
+ }
1357
+ if (isset($data['license'])) {
1358
+ if (is_array($data['license'])) {
1359
+ $this->setLicense($data['license']['_content'], $data['license']['attribs']['uri']);
1360
+ } else {
1361
+ $this->setLicense($data['license']);
1362
+ }
1363
+ }
1364
+ if (isset($data['version'])) {
1365
+ $this->setVersion($data['version']['release']);
1366
+ }
1367
+ if (isset($data['stability'])) {
1368
+ $this->setStability($data['stability']['release']);
1369
+ }
1370
+ if (isset($data['notes'])) {
1371
+ $this->setNotes($data['notes']);
1372
+ }
1373
+ if (isset($data['date'])) {
1374
+ $this->setDate($data['date']);
1375
+ }
1376
+ if (isset($data['time'])) {
1377
+ $this->setTime($data['time']);
1378
+ }
1379
+
1380
+ // Import authors
1381
+ $authors = array();
1382
+ $authorRoles = array('lead', 'developer', 'contributor', 'helper');
1383
+ foreach ($authorRoles as $authorRole) {
1384
+ if (isset($data[$authorRole])) {
1385
+ $authorList = $data[$authorRole];
1386
+ if (!is_array($authorList) || isset($authorList['name'])) {
1387
+ $authorList = array($authorList);
1388
+ }
1389
+ foreach ($authorList as $authorRawData) {
1390
+ $author = array();
1391
+ $author['name'] = $authorRawData['name'];
1392
+ $author['user'] = $authorRawData['user'];
1393
+ $author['email'] = $authorRawData['email'];
1394
+ array_push($authors, $author);
1395
+ }
1396
+ }
1397
+ }
1398
+ $this->setAuthors($authors);
1399
+
1400
+ // Import dependencies
1401
+ $packages = array();
1402
+ $extensions = array();
1403
+ if (isset($data['dependencies']) && is_array($data['dependencies'])) {
1404
+ $dependencySections = array('required', 'optional');
1405
+ $elementTypes = array('package', 'extension');
1406
+ foreach ($dependencySections as $dependencySection) {
1407
+ if (isset($data['dependencies'][$dependencySection])) {
1408
+ // Handle required PHP version
1409
+ if ($dependencySection == 'required' && isset($data['dependencies']['required']['php'])) {
1410
+ $this->setDependencyPhpVersion($data['dependencies']['required']['php']['min'], $data['dependencies']['required']['php']['max']);
1411
+ }
1412
+ // Handle extensions
1413
+ if (isset($data['dependencies'][$dependencySection]['extension'])) {
1414
+ $extensionList = $data['dependencies'][$dependencySection]['extension'];
1415
+ if (!is_array($extensionList) || isset($extensionList['name'])) {
1416
+ $extensionList = array($extensionList);
1417
+ }
1418
+ foreach ($extensionList as $extensionRawData) {
1419
+ $extension = array();
1420
+ $extension['name'] = $extensionRawData['name'];
1421
+ $extension['min_version'] = isset($extensionRawData['min']) ? $extensionRawData['min'] : null;
1422
+ $extension['max_version'] = isset($extensionRawData['max']) ? $extensionRawData['max'] : null;
1423
+ array_push($extensions, $extension);
1424
+ }
1425
+ }
1426
+ // Handle packages
1427
+ if (isset($data['dependencies'][$dependencySection]['package'])) {
1428
+ $packageList = $data['dependencies'][$dependencySection]['package'];
1429
+ if (!is_array($packageList) || isset($packageList['name'])) {
1430
+ $packageList = array($packageList);
1431
+ }
1432
+ foreach ($packageList as $packageRawData) {
1433
+ $package = array();
1434
+ $package['name'] = $packageRawData['name'];
1435
+ $package['channel'] = $this->convertChannelFromV1x($packageRawData['channel']);
1436
+ $package['min_version'] = isset($packageRawData['min']) ? $packageRawData['min'] : null;
1437
+ $package['max_version'] = isset($packageRawData['max']) ? $packageRawData['max'] : null;
1438
+ array_push($packages, $package);
1439
+ }
1440
+ }
1441
+ }
1442
+ }
1443
+ }
1444
+ $this->setDependencyPackages($packages);
1445
+ $this->setDependencyPhpExtensions($extensions);
1446
+
1447
+ // Import contents
1448
+ if (isset($data['contents']) && is_array($data['contents']) && is_array($data['contents']['dir'])) {
1449
+ // Handle files
1450
+ $root = $data['contents']['dir'];
1451
+ if (isset($data['contents']['dir']['file'])) {
1452
+ $fileList = $data['contents']['dir']['file'];
1453
+ if (!is_array($fileList) || isset($fileList['attribs'])) {
1454
+ $fileList = array($fileList);
1455
+ }
1456
+ foreach ($fileList as $fileRawData) {
1457
+ $targetName = $fileRawData['attribs']['role'];
1458
+ $parentTargetNode = $this->_getNode('target', $this->_packageXml->contents, $targetName);
1459
+ $filePath = $fileRawData['attribs']['name'];
1460
+ $filePathParts = explode('/', $filePath);
1461
+ $fileName = array_pop($filePathParts);
1462
+ $parentDirNode = null;
1463
+ if (!empty($filePathParts)) {
1464
+ $parentDirNode = $parentTargetNode;
1465
+ foreach ($filePathParts as $directoryName) {
1466
+ $parentDirNode = $this->_getNode('dir', $parentDirNode, $directoryName);
1467
+ }
1468
+ } else {
1469
+ $parentDirNode = $this->_getNode('dir', $parentTargetNode, '.');
1470
+ }
1471
+ $fileNode = $parentDirNode->addChild('file');
1472
+ $fileNode->addAttribute('name', $fileName);
1473
+ $fileNode->addAttribute('hash', $fileRawData['attribs']['md5sum']);
1474
+ }
1475
+ }
1476
+ }
1477
+
1478
+ return $this;
1479
+ }
1480
+
1481
+ /**
1482
+ * Convert package channel in order for it to be compatible with current version of Magento Connect Manager
1483
+ *
1484
+ * @param string $channel
1485
+ *
1486
+ * @return string
1487
+ */
1488
+ public function convertChannelFromV1x($channel)
1489
+ {
1490
+ $channelMap = array(
1491
+ 'connect.magentocommerce.com/community' => 'community',
1492
+ 'connect.magentocommerce.com/core' => 'community'
1493
+ );
1494
+ if (!empty($channel) && isset($channelMap[$channel])) {
1495
+ $channel = $channelMap[$channel];
1496
+ }
1497
+ return $channel;
1498
+ }
1499
+ }
downloader/lib/Mage/Connect/Package/Extension.php ADDED
@@ -0,0 +1 @@
 
1
+
downloader/lib/Mage/Connect/Package/Hotfix.php ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to work with Magento Connect Hotfix
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+
35
+ class Mage_Connect_Package_Hotfix extends Mage_Connect_Package
36
+ {
37
+
38
+ /**
39
+ * Initializes an empty package object
40
+ *
41
+ * @param null|string $definition optional package definition xml
42
+ * @return Mage_Connect_Package
43
+ */
44
+ protected function _init($definition=null)
45
+ {
46
+
47
+ if (!is_null($definition)) {
48
+ $this->_packageXml = simplexml_load_string($definition);
49
+ } else {
50
+ $packageXmlStub = <<<END
51
+ <?xml version="1.0"?>
52
+ <package>
53
+ <name />
54
+ <version />
55
+ <stability />
56
+ <license />
57
+ <channel />
58
+ <extends />
59
+ <summary />
60
+ <description />
61
+ <notes />
62
+ <authors />
63
+ <date />
64
+ <time />
65
+ <replace />
66
+ <compatible />
67
+ <dependencies />
68
+ </package>
69
+ END;
70
+ $this->_packageXml = simplexml_load_string($packageXmlStub);
71
+ }
72
+ return $this;
73
+ }
74
+
75
+ /**
76
+ * Add content to node <replace/>
77
+ *
78
+ * @return Mage_Connect_Package_Hotfix
79
+ */
80
+ public function addReplace($path, $targetName)
81
+ {
82
+ $found = false;
83
+ $parent = $this->_getNode('target', $this->_packageXml->replace, $targetName);
84
+ $path = str_replace('\\', '/', $path);
85
+ $directories = explode('/', dirname($path));
86
+ foreach ($directories as $directory) {
87
+ $parent = $this->_getNode('dir', $parent, $directory);
88
+ }
89
+ $fileName = basename($path);
90
+ if ($fileName!='') {
91
+ $fileNode = $parent->addChild('file');
92
+ $fileNode->addAttribute('name', $fileName);
93
+ }
94
+ return $this;
95
+ }
96
+
97
+ /**
98
+ * Add directory recursively (with subdirectory and file).
99
+ * Exclude and Include can be add using Regular Expression.
100
+ *
101
+ * @param string $targetName Target name
102
+ * @param string $targetDir Path for target name
103
+ * @param string $path Path to directory
104
+ * @param string $exclude Exclude
105
+ * @param string $include Include
106
+ * @return Mage_Connect_Package
107
+ */
108
+ public function addReplaceDir($targetName, $targetDir, $path, $exclude=null, $include=null)
109
+ {
110
+ $targetDirLen = strlen($targetDir);
111
+ //get all subdirectories and files.
112
+ $entries = @glob($targetDir.$path.DS."*");
113
+ if (!empty($entries)) {
114
+ foreach ($entries as $entry) {
115
+ $filePath = substr($entry, $targetDirLen);
116
+ if (!empty($include) && !preg_match($include, $filePath)) {
117
+ continue;
118
+ }
119
+ if (!empty($ignore) && preg_match($exclude, $filePath)) {
120
+ continue;
121
+ }
122
+ if (is_dir($entry)) {
123
+ $baseName = basename($entry);
124
+ if ('.'===$baseName || '..'===$baseName) {
125
+ continue;
126
+ }
127
+ //for subdirectory call method recursively
128
+ $this->addReplaceDir($targetName, $targetDir, $filePath, $exclude, $include);
129
+ } elseif (is_file($entry)) {
130
+ $this->addReplace($filePath, $targetName);
131
+ }
132
+ }
133
+ }
134
+ return $this;
135
+ }
136
+
137
+ }
downloader/lib/Mage/Connect/Package/Maintainer.php ADDED
@@ -0,0 +1 @@
 
1
+
downloader/lib/Mage/Connect/Package/Reader.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to get package.xml from different places.
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Connect_Package_Reader
35
+ {
36
+
37
+ /**
38
+ * Name of package file
39
+ */
40
+ const DEFAULT_NAME_PACKAGE = 'package.xml';
41
+
42
+ /**
43
+ * Temporary dir for extract DEFAULT_NAME_PACKAGE.
44
+ */
45
+ const PATH_TO_TEMPORARY_DIRECTORY = 'var/package/tmp/';
46
+
47
+ /**
48
+ * Current path to file.
49
+ *
50
+ * @var string
51
+ */
52
+ protected $_file = '';
53
+
54
+ /**
55
+ * Archivator is used for extract DEFAULT_NAME_PACKAGE.
56
+ *
57
+ * @var Mage_Archive
58
+ */
59
+ protected $_archivator = null;
60
+
61
+ /**
62
+ * Constructor initializes $_file.
63
+ *
64
+ * @param string $file
65
+ * @return Mage_Connect_Package_Reader
66
+ */
67
+ public function __construct($file='')
68
+ {
69
+ if ($file) {
70
+ $this->_file = $file;
71
+ } else {
72
+ $this->_file = self::DEFAULT_NAME_PACKAGE;
73
+ }
74
+ return $this;
75
+ }
76
+
77
+ /**
78
+ * Retrieve archivator.
79
+ *
80
+ * @return Mage_Archive
81
+ */
82
+ protected function _getArchivator()
83
+ {
84
+ if (is_null($this->_archivator)) {
85
+ $this->_archivator = new Mage_Archive();
86
+ }
87
+ return $this->_archivator;
88
+ }
89
+
90
+ /**
91
+ * Open file directly or from archive and return his content.
92
+ *
93
+ * @return string Content of file $file
94
+ */
95
+ public function load()
96
+ {
97
+ if (!is_file($this->_file) || !is_readable($this->_file)) {
98
+ throw new Exception('Invalid package file specified.');
99
+ }
100
+ if ($this->_getArchivator()->isArchive($this->_file)) {
101
+ @mkdir(self::PATH_TO_TEMPORARY_DIRECTORY, 0777, true);
102
+ $this->_file = $this->_getArchivator()->extract(
103
+ self::DEFAULT_NAME_PACKAGE,
104
+ $this->_file,
105
+ self::PATH_TO_TEMPORARY_DIRECTORY
106
+ );
107
+ }
108
+ $xmlContent = $this->_readFile();
109
+ return $xmlContent;
110
+ }
111
+
112
+ /**
113
+ * Read content file.
114
+ *
115
+ * @return string Content of file $file
116
+ */
117
+ protected function _readFile()
118
+ {
119
+ $handle = fopen($this->_file, 'r');
120
+ try {
121
+ $data = $this->_loadResource($handle);
122
+ } catch (Mage_Exception $e) {
123
+ fclose($handle);
124
+ throw $e;
125
+ }
126
+ fclose($handle);
127
+ return $data;
128
+ }
129
+
130
+ /**
131
+ * Loads a package from specified resource
132
+ *
133
+ * @param resource $resource only file resources are supported at the moment
134
+ * @return Mage_Connect_Package
135
+ */
136
+ protected function _loadResource(&$resource)
137
+ {
138
+ $data = '';
139
+ //var_dump("====", $res, get_resource_type($resource));
140
+ if ('stream' === get_resource_type($resource)) {
141
+ while (!feof($resource)) {
142
+ $data .= fread($resource, 10240);
143
+ }
144
+ } else {
145
+ throw new Mage_Exception('Unsupported resource type');
146
+ }
147
+ return $data;
148
+ }
149
+
150
+ }
downloader/lib/Mage/Connect/Package/Target.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to get targets and their basepath from target.xml.
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+
35
+ class Mage_Connect_Package_Target
36
+ {
37
+
38
+ /**
39
+ * Object contains all contents from target.xml.
40
+ *
41
+ * @var array
42
+ */
43
+ protected $_targetMap=null;
44
+
45
+ /**
46
+ * Cache for targets.
47
+ *
48
+ * @var array
49
+ */
50
+ protected $_targets;
51
+
52
+ /**
53
+ * Retrieve content from target.xml.
54
+ *
55
+ * @return SimpleXMLElement
56
+ */
57
+ protected function _getTargetMap()
58
+ {
59
+ if (is_null($this->_targetMap)) {
60
+ $this->_targetMap = array();
61
+ $this->_targetMap[] = array('name'=>"magelocal" ,'label'=>"Magento Local module file" , 'uri'=>"./app/code/local");
62
+ $this->_targetMap[] = array('name'=>"magecommunity" ,'label'=>"Magento Community module file" , 'uri'=>"./app/code/community");
63
+ $this->_targetMap[] = array('name'=>"magecore" ,'label'=>"Magento Core team module file" , 'uri'=>"./app/code/core");
64
+ $this->_targetMap[] = array('name'=>"magedesign" ,'label'=>"Magento User Interface (layouts, templates)" , 'uri'=>"./app/design");
65
+ $this->_targetMap[] = array('name'=>"mageetc" ,'label'=>"Magento Global Configuration" , 'uri'=>"./app/etc");
66
+ $this->_targetMap[] = array('name'=>"magelib" ,'label'=>"Magento PHP Library file" , 'uri'=>"./lib");
67
+ $this->_targetMap[] = array('name'=>"magelocale" ,'label'=>"Magento Locale language file" , 'uri'=>"./app/locale");
68
+ $this->_targetMap[] = array('name'=>"magemedia" ,'label'=>"Magento Media library" , 'uri'=>"./media");
69
+ $this->_targetMap[] = array('name'=>"mageskin" ,'label'=>"Magento Theme Skin (Images, CSS, JS)" , 'uri'=>"./skin");
70
+ $this->_targetMap[] = array('name'=>"mageweb" ,'label'=>"Magento Other web accessible file" , 'uri'=>".");
71
+ $this->_targetMap[] = array('name'=>"magetest" ,'label'=>"Magento PHPUnit test" , 'uri'=>"./tests");
72
+ $this->_targetMap[] = array('name'=>"mage" ,'label'=>"Magento other" , 'uri'=>".");
73
+ }
74
+ return $this->_targetMap;
75
+ }
76
+
77
+ /**
78
+ * Retrieve targets as associative array from target.xml.
79
+ *
80
+ * @return array
81
+ */
82
+ public function getTargets()
83
+ {
84
+ if (!is_array($this->_targets)) {
85
+ $this->_targets = array();
86
+ if($this->_getTargetMap()) {
87
+ foreach ($this->_getTargetMap() as $_target) {
88
+ $this->_targets[$_target['name']] = (string)$_target['uri'];
89
+ }
90
+ }
91
+ }
92
+ return $this->_targets;
93
+ }
94
+
95
+ /**
96
+ * Retrieve tragets with label for select options.
97
+ *
98
+ * @return array
99
+ */
100
+ public function getLabelTargets()
101
+ {
102
+ $targets = array();
103
+ foreach ($this->_getTargetMap() as $_target) {
104
+ $targets[$_target['name']] = $_target['label'];
105
+ }
106
+ return $targets;
107
+ }
108
+
109
+ /**
110
+ * Get uri by target's name.
111
+ *
112
+ * @param string $name
113
+ * @return string
114
+ */
115
+ public function getTargetUri($name)
116
+ {
117
+ foreach ($this->getTargets() as $_name=>$_uri) {
118
+ if ($name == $_name) {
119
+ return $_uri;
120
+ }
121
+ }
122
+ return '';
123
+ }
124
+
125
+
126
+ }
downloader/lib/Mage/Connect/Package/VO.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ class Mage_Connect_Package_VO implements Iterator
28
+ {
29
+ protected $properties = array(
30
+ 'name' => '',
31
+ 'package_type_vesrion' => '',
32
+ 'cahnnel' => '',
33
+ 'extends' => '',
34
+ 'summary' => '',
35
+ 'description' => '',
36
+ 'authors' => '',
37
+ 'date' => '',
38
+ 'time' => '',
39
+ 'version' => '',
40
+ 'stability' => 'dev',
41
+ 'license' => '',
42
+ 'license_uri' => '',
43
+ 'contents' => '',
44
+ 'compatible' => '',
45
+ 'hotfix' => ''
46
+ );
47
+
48
+ public function rewind() {
49
+ reset($this->properties);
50
+ }
51
+
52
+ public function valid() {
53
+ return current($this->properties) !== false;
54
+ }
55
+
56
+ public function key() {
57
+ return key($this->properties);
58
+ }
59
+
60
+ public function current() {
61
+ return current($this->properties);
62
+ }
63
+
64
+ public function next() {
65
+ next($this->properties);
66
+ }
67
+
68
+ public function __get($var)
69
+ {
70
+ if (isset($this->properties[$var])) {
71
+ return $this->properties[$var];
72
+ }
73
+ return null;
74
+ }
75
+
76
+ public function __set($var, $value)
77
+ {
78
+ if (is_string($value)) {
79
+ $value = trim($value);
80
+ }
81
+ if (isset($this->properties[$var])) {
82
+ if ($value === null) {
83
+ $value = '';
84
+ }
85
+ $this->properties[$var] = $value;
86
+ }
87
+ }
88
+
89
+ public function toArray()
90
+ {
91
+ return $this->properties;
92
+ }
93
+
94
+ }
95
+
96
+
downloader/lib/Mage/Connect/Package/Writer.php ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to create archive.
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Connect_Package_Writer
35
+ {
36
+
37
+ /**
38
+ * Name of package configuration file
39
+ */
40
+ const DEFAULT_NAME_PACKAGE_CONFIG = 'package.xml';
41
+
42
+ /**
43
+ * Temporary dir for extract DEFAULT_NAME_PACKAGE.
44
+ */
45
+ const PATH_TO_TEMPORARY_DIRECTORY = 'var/package/tmp/';
46
+
47
+ /**
48
+ * Files are used in package.
49
+ *
50
+ * @var array
51
+ */
52
+ protected $_files = array();
53
+
54
+ /**
55
+ * Archivator is used for extract DEFAULT_NAME_PACKAGE.
56
+ *
57
+ * @var Mage_Archive
58
+ */
59
+ protected $_archivator = null;
60
+
61
+ /**
62
+ * Name of package with extension. Extension should be only one.
63
+ * "package.tar.gz" is not ability, only "package.tgz".
64
+ *
65
+ * @var string
66
+ */
67
+ protected $_namePackage = 'package';
68
+
69
+ /**
70
+ * Temporary directory where package is situated.
71
+ *
72
+ * @var string
73
+ */
74
+ protected $_temporaryPackageDir = '';
75
+
76
+ /**
77
+ * Path to archive with package.
78
+ *
79
+ * @var mixed
80
+ */
81
+ protected $_pathToArchive = '';
82
+
83
+ /**
84
+ * Constructor initializes $_file.
85
+ *
86
+ * @param array $files
87
+ * @param string $namePackage
88
+ * @return Mage_Connect_Package_Reader
89
+ */
90
+ public function __construct($files, $namePackage='')
91
+ {
92
+ $this->_files = $files;
93
+ $this->_namePackage = $namePackage;
94
+ return $this;
95
+ }
96
+
97
+ /**
98
+ * Retrieve archivator.
99
+ *
100
+ * @return Mage_Archive
101
+ */
102
+ protected function _getArchivator()
103
+ {
104
+ if (is_null($this->_archivator)) {
105
+ $this->_archivator = new Mage_Archive();
106
+ }
107
+ return $this->_archivator;
108
+ }
109
+
110
+ /**
111
+ * Create dir in PATH_TO_TEMPORARY_DIRECTORY and move all files
112
+ * to this dir.
113
+ *
114
+ * @return Mage_Connect_Package_Writer
115
+ */
116
+ public function composePackage()
117
+ {
118
+ @mkdir(self::PATH_TO_TEMPORARY_DIRECTORY, 0777, true);
119
+ $root = self::PATH_TO_TEMPORARY_DIRECTORY . basename($this->_namePackage);
120
+ @mkdir($root, 0777, true);
121
+ foreach ($this->_files as $file) {
122
+
123
+ if (is_dir($file) || is_file($file)) {
124
+ $fileName = basename($file);
125
+ $filePath = dirname($file);
126
+ @mkdir($root . DS . $filePath, 0777, true);
127
+ if (is_file($file)) {
128
+ copy($file, $root . DS . $filePath . DS . $fileName);
129
+ } else {
130
+ @mkdir($root . DS . $filePath . $fileName, 0777);
131
+ }
132
+ }
133
+ }
134
+ $this->_temporaryPackageDir = $root;
135
+ return $this;
136
+ }
137
+
138
+ /**
139
+ * Add package.xml to temporary package directory.
140
+ *
141
+ * @param $content
142
+ * @return Mage_Connect_Package_Writer
143
+ */
144
+ public function addPackageXml($content)
145
+ {
146
+ file_put_contents($this->_temporaryPackageDir . DS . self::DEFAULT_NAME_PACKAGE_CONFIG, $content);
147
+ return $this;
148
+ }
149
+
150
+ /**
151
+ * Archives package.
152
+ *
153
+ * @return Mage_Connect_Package_Writer
154
+ */
155
+ public function archivePackage()
156
+ {
157
+ $this->_pathToArchive = $this->_getArchivator()->pack(
158
+ $this->_temporaryPackageDir,
159
+ $this->_namePackage.'.tgz',
160
+ true);
161
+
162
+ //delete temporary dir
163
+ Mage_System_Dirs::rm(array("-r", $this->_temporaryPackageDir));
164
+ return $this;
165
+ }
166
+
167
+ /**
168
+ * Getter for pathToArchive
169
+ *
170
+ * @return string
171
+ */
172
+ public function getPathToArchive()
173
+ {
174
+ return $this->_pathToArchive;
175
+ }
176
+
177
+ }
downloader/lib/Mage/Connect/Packager.php ADDED
@@ -0,0 +1,909 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to manipulate with packages
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+
35
+ class Mage_Connect_Packager
36
+ {
37
+ const CONFIG_FILE_NAME='downloader/connect.cfg';
38
+ const CACHE_FILE_NAME='downloader/cache.cfg';
39
+
40
+ protected $install_states = array(
41
+ 'install' => 'Ready to install',
42
+ 'upgrade' => 'Ready to upgrade',
43
+ 'already_installed' => 'Already installed',
44
+ 'wrong_version' => 'Wrong version',
45
+ );
46
+
47
+ /**
48
+ * Constructor
49
+ * @param Mage_connect_Config $config
50
+ */
51
+ public function __construct()
52
+ {
53
+
54
+ }
55
+
56
+ /**
57
+ *
58
+ * @var Mage_Archive
59
+ */
60
+ protected $_archiver = null;
61
+ protected $_http = null;
62
+
63
+
64
+
65
+ /**
66
+ *
67
+ * @return Mage_Archive
68
+ */
69
+ public function getArchiver()
70
+ {
71
+ if(is_null($this->_archiver)) {
72
+ $this->_archiver = new Mage_Archive();
73
+ }
74
+ return $this->_archiver;
75
+ }
76
+
77
+ public function getDownloader()
78
+ {
79
+ if(is_null($this->_http)) {
80
+ $this->_http = Mage_HTTP_Client::getInstance();
81
+ }
82
+ return $this->_http;
83
+ }
84
+
85
+
86
+ public function getRemoteConf($ftpString)
87
+ {
88
+ $ftpObj = new Mage_Connect_Ftp();
89
+ $ftpObj->connect($ftpString);
90
+ $cfgFile = self::CONFIG_FILE_NAME;
91
+ $cacheFile = self::CACHE_FILE_NAME;
92
+
93
+
94
+ $wd = $ftpObj->getcwd();
95
+
96
+ $remoteConfigExists = $ftpObj->fileExists($cfgFile);
97
+ $tempConfigFile = tempnam(sys_get_temp_dir(),'conf');
98
+ if(!$remoteConfigExists) {
99
+ $remoteCfg = new Mage_Connect_Config($tempConfigFile);
100
+ $remoteCfg->store();
101
+ $ftpObj->upload($cfgFile, $tempConfigFile);
102
+ } else {
103
+ $ftpObj->get($tempConfigFile, $cfgFile);
104
+ $remoteCfg = new Mage_Connect_Config($tempConfigFile);
105
+ }
106
+
107
+ $ftpObj->chdir($wd);
108
+
109
+ $remoteCacheExists = $ftpObj->fileExists($cacheFile);
110
+ $tempCacheFile = tempnam(sys_get_temp_dir(),'cache');
111
+
112
+ if(!$remoteCacheExists) {
113
+ $remoteCache = new Mage_Connect_Singleconfig($tempCacheFile);
114
+ $remoteCache->clear();
115
+ $ftpObj->upload($cacheFile, $tempCacheFile);
116
+ } else {
117
+ $ftpObj->get($tempCacheFile, $cacheFile);
118
+ $remoteCache = new Mage_Connect_Singleconfig($tempCacheFile);
119
+ }
120
+ $ftpObj->chdir($wd);
121
+ return array($remoteCache, $remoteCfg, $ftpObj);
122
+ }
123
+
124
+
125
+ public function getRemoteCache($ftpString)
126
+ {
127
+
128
+ $ftpObj = new Mage_Connect_Ftp();
129
+ $ftpObj->connect($ftpString);
130
+ $remoteConfigExists = $ftpObj->fileExists(self::CACHE_FILE_NAME);
131
+ if(!$remoteConfigExists) {
132
+ $configFile=tempnam(sys_get_temp_dir(),'conf');
133
+ $remoteCfg = new Mage_Connect_Singleconfig($configFile);
134
+ $remoteCfg->clear();
135
+ $ftpObj->upload(self::CACHE_FILE_NAME, $configFile);
136
+ } else {
137
+ $configFile=tempnam(sys_get_temp_dir(),'conf');
138
+ $ftpObj->get($configFile, self::CACHE_FILE_NAME);
139
+ $remoteCfg = new Mage_Connect_Singleconfig($configFile);
140
+ }
141
+ return array($remoteCfg, $ftpObj);
142
+ }
143
+
144
+
145
+ public function getRemoteConfig($ftpString)
146
+ {
147
+ $ftpObj = new Mage_Connect_Ftp();
148
+ $ftpObj->connect($ftpString);
149
+ $cfgFile = self::CONFIG_FILE_NAME;
150
+
151
+ $wd = $ftpObj->getcwd();
152
+ $remoteConfigExists = $ftpObj->fileExists($cfgFile);
153
+ $tempConfigFile = tempnam(sys_get_temp_dir(),'conf_');
154
+ if(!$remoteConfigExists) {
155
+ $remoteCfg = new Mage_Connect_Config($tempConfigFile);
156
+ $remoteCfg->store();
157
+ $ftpObj->upload($cfgFile, $tempConfigFile);
158
+ } else {
159
+ $ftpObj->get($tempConfigFile, $cfgFile);
160
+ $remoteCfg = new Mage_Connect_Config($tempConfigFile);
161
+ }
162
+ $ftpObj->chdir($wd);
163
+ return array($remoteCfg, $ftpObj);
164
+ }
165
+
166
+ public function writeToRemoteCache($cache, $ftpObj)
167
+ {
168
+ $wd = $ftpObj->getcwd();
169
+ $ftpObj->upload(self::CACHE_FILE_NAME, $cache->getFilename());
170
+ @unlink($cache->getFilename());
171
+ $ftpObj->chdir($wd);
172
+ }
173
+
174
+ public function writeToRemoteConfig($cache, $ftpObj)
175
+ {
176
+ $wd = $ftpObj->getcwd();
177
+ $ftpObj->upload(self::CONFIG_FILE_NAME, $cache->getFilename());
178
+ @unlink($cache->getFilename());
179
+ $ftpObj->chdir($wd);
180
+ }
181
+
182
+ /**
183
+ * Remove empty directories recursively up
184
+ * @param string $dir
185
+ * @param Mage_Connect_Ftp $ftp
186
+ */
187
+ protected function removeEmptyDirectory($dir, $ftp = null)
188
+ {
189
+ if ($ftp) {
190
+ if (count($ftp->nlist($dir))==0) {
191
+ if ($ftp->rmdir($dir)) {
192
+ $this->removeEmptyDirectory(dirname($dir), $ftp);
193
+ }
194
+ }
195
+ } else {
196
+ if (@rmdir($dir)) {
197
+ $this->removeEmptyDirectory(dirname($dir), $ftp);
198
+ }
199
+ }
200
+ }
201
+
202
+ /**
203
+ *
204
+ * @param $chanName
205
+ * @param $package
206
+ * @param Mage_Connect_Singleconfig $cacheObj
207
+ * @param Mage_Connect_Config $configObj
208
+ * @return unknown_type
209
+ */
210
+ public function processUninstallPackage($chanName, $package, $cacheObj, $configObj)
211
+ {
212
+ $package = $cacheObj->getPackageObject($chanName, $package);
213
+ $contents = $package->getContents();
214
+
215
+ $targetPath = rtrim($configObj->magento_root, "\\/");
216
+ foreach($contents as $file) {
217
+ $fileName = basename($file);
218
+ $filePath = dirname($file);
219
+ $dest = $targetPath . DIRECTORY_SEPARATOR . $filePath . DIRECTORY_SEPARATOR . $fileName;
220
+ if(@file_exists($dest)) {
221
+ @unlink($dest);
222
+ $this->removeEmptyDirectory(dirname($dest));
223
+ }
224
+ }
225
+
226
+ $destDir = $targetPath . DS . Mage_Connect_Package::PACKAGE_XML_DIR;
227
+ $destFile = $package->getReleaseFilename() . '.xml';
228
+ @unlink($destDir . DS . $destFile);
229
+ }
230
+
231
+ /**
232
+ *
233
+ * @param $chanName
234
+ * @param $package
235
+ * @param Mage_Connect_Singleconfig $cacheObj
236
+ * @param Mage_Connect_Ftp $ftp
237
+ * @return unknown_type
238
+ */
239
+ public function processUninstallPackageFtp($chanName, $package, $cacheObj, $ftp)
240
+ {
241
+ $ftpDir = $ftp->getcwd();
242
+ $package = $cacheObj->getPackageObject($chanName, $package);
243
+ $contents = $package->getContents();
244
+ foreach($contents as $file) {
245
+ $res = $ftp->delete($file);
246
+ $this->removeEmptyDirectory(dirname($file), $ftp);
247
+ }
248
+ $remoteXml = Mage_Connect_Package::PACKAGE_XML_DIR . DS . $package->getReleaseFilename() . '.xml';
249
+ $ftp->delete($remoteXml);
250
+ $ftp->chdir($ftpDir);
251
+ }
252
+
253
+ /**
254
+ * Validation of mode permissions
255
+ *
256
+ * @param int $mode
257
+ * @return int
258
+ */
259
+ protected function validPermMode($mode)
260
+ {
261
+ $mode = intval($mode);
262
+ if ($mode < 73 || $mode > 511) {
263
+ return false;
264
+ }
265
+ return true;
266
+ }
267
+ /**
268
+ *
269
+ * Return correct global dir mode in octal representation
270
+ *
271
+ * @param Maged_Model_Config $config
272
+ * @return int
273
+ */
274
+ protected function _getDirMode($config)
275
+ {
276
+ if ($this->validPermMode($config->global_dir_mode)) {
277
+ return $config->global_dir_mode;
278
+ } else {
279
+ return $config->getDefaultValue('global_dir_mode');
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Return global file mode in octal representation
285
+ *
286
+ * @param Maged_Model_Config $config
287
+ * @return int
288
+ */
289
+ protected function _getFileMode($config)
290
+ {
291
+ if ($this->validPermMode($config->global_file_mode)) {
292
+ return $config->global_file_mode;
293
+ } else {
294
+ return $config->getDefaultValue('global_file_mode');
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Convert FTP path
300
+ *
301
+ * @param string $str
302
+ * @return string
303
+ */
304
+ protected function convertFtpPath($str)
305
+ {
306
+ return str_replace("\\", "/", $str);
307
+ }
308
+
309
+ public function processInstallPackageFtp($package, $file, $configObj, $ftp)
310
+ {
311
+ $ftpDir = $ftp->getcwd();
312
+ $contents = $package->getContents();
313
+ $arc = $this->getArchiver();
314
+ $target = dirname($file).DS.$package->getReleaseFilename();
315
+ @mkdir($target, 0777, true);
316
+ $tar = $arc->unpack($file, $target);
317
+ $modeFile = $this->_getFileMode($configObj);
318
+ $modeDir = $this->_getDirMode($configObj);
319
+ foreach($contents as $file) {
320
+ $fileName = basename($file);
321
+ $filePath = $this->convertFtpPath(dirname($file));
322
+ $source = $tar.DS.$file;
323
+ if (file_exists($source) && is_file($source)) {
324
+ $args = array(ltrim($file,"/"), $source);
325
+ if($modeDir||$modeFile) {
326
+ $args[] = $modeDir;
327
+ $args[] = $modeFile;
328
+ }
329
+ call_user_func_array(array($ftp,'upload'), $args);
330
+ }
331
+ }
332
+
333
+ $localXml = $tar . Mage_Connect_Package_Reader::DEFAULT_NAME_PACKAGE;
334
+ if (is_file($localXml)) {
335
+ $remoteXml = Mage_Connect_Package::PACKAGE_XML_DIR . DS . $package->getReleaseFilename() . '.xml';
336
+ $ftp->upload($remoteXml, $localXml, $modeDir, $modeFile);
337
+ }
338
+
339
+ $ftp->chdir($ftpDir);
340
+ Mage_System_Dirs::rm(array("-r",$target));
341
+ }
342
+
343
+ /**
344
+ * Package installation to FS
345
+ * @param Mage_Connect_Package $package
346
+ * @param string $file
347
+ * @return void
348
+ * @throws Exception
349
+ */
350
+ public function processInstallPackage($package, $file, $configObj)
351
+ {
352
+ $contents = $package->getContents();
353
+ $arc = $this->getArchiver();
354
+ $target = dirname($file).DS.$package->getReleaseFilename();
355
+ @mkdir($target, 0777, true);
356
+ $tar = $arc->unpack($file, $target);
357
+ $modeFile = $this->_getFileMode($configObj);
358
+ $modeDir = $this->_getDirMode($configObj);
359
+ foreach($contents as $file) {
360
+ $fileName = basename($file);
361
+ $filePath = dirname($file);
362
+ $source = $tar.DS.$file;
363
+ $targetPath = rtrim($configObj->magento_root, "\\/");
364
+ @mkdir($targetPath. DS . $filePath, $modeDir, true);
365
+ $dest = $targetPath . DS . $filePath . DS . $fileName;
366
+ if (is_file($source)) {
367
+ @copy($source, $dest);
368
+ if($modeFile) {
369
+ @chmod($dest, $modeFile);
370
+ }
371
+ } else {
372
+ @mkdir($dest, $modeDir);
373
+ }
374
+ }
375
+
376
+ $packageXml = $tar . Mage_Connect_Package_Reader::DEFAULT_NAME_PACKAGE;
377
+ if (is_file($packageXml)) {
378
+ $destDir = $targetPath . DS . Mage_Connect_Package::PACKAGE_XML_DIR;
379
+ $destFile = $package->getReleaseFilename() . '.xml';
380
+ $dest = $destDir . DS . $destFile;
381
+
382
+ @copy($packageXml, $dest);
383
+ @chmod($dest, $modeFile);
384
+ }
385
+
386
+ Mage_System_Dirs::rm(array("-r",$target));
387
+ }
388
+
389
+
390
+ /**
391
+ * Get local modified files
392
+ * @param $chanName
393
+ * @param $package
394
+ * @param $cacheObj
395
+ * @param $configObj
396
+ * @return array
397
+ */
398
+ public function getLocalModifiedFiles($chanName, $package, $cacheObj, $configObj)
399
+ {
400
+ $p = $cacheObj->getPackageObject($chanName, $package);
401
+ $hashContents = $p->getHashContents();
402
+ $listModified = array();
403
+ foreach ($hashContents as $file=>$hash) {
404
+ if (md5_file($configObj->magento_root . DS . $file)!==$hash) {
405
+ $listModified[] = $file;
406
+ }
407
+ }
408
+ return $listModified;
409
+ }
410
+
411
+ /**
412
+ * Get remote modified files
413
+ *
414
+ * @param $chanName
415
+ * @param $package
416
+ * @param $cacheObj
417
+ * @param Mage_Connect_Ftp $ftp
418
+ * @return array
419
+ */
420
+ public function getRemoteModifiedFiles($chanName, $package, $cacheObj, $ftp)
421
+ {
422
+ $p = $cacheObj->getPackageObject($chanName, $package);
423
+ $hashContents = $p->getHashContents();
424
+ $listModified = array();
425
+ foreach ($hashContents as $file=>$hash) {
426
+ $localFile = uniqid("temp_remote_");
427
+ if(!$ftp->fileExists($file)) {
428
+ continue;
429
+ }
430
+ $ftp->get($localFile, $file);
431
+ if (file_exists($localFile) && md5_file($localFile)!==$hash) {
432
+ $listModified[] = $file;
433
+ }
434
+ @unlink($localFile);
435
+ }
436
+ return $listModified;
437
+ }
438
+
439
+
440
+ /**
441
+ *
442
+ * Get upgrades list
443
+ *
444
+ * @param string/array $channels
445
+ * @param Mage_Connect_Singleconfig $cacheObject
446
+ * @param Mage_Connect_Rest $restObj optional
447
+ * @param bool $checkConflicts
448
+ * @return array
449
+ */
450
+ public function getUpgradesList($channels, $cacheObject, $configObj, $restObj = null, $checkConflicts = false)
451
+ {
452
+ if(is_scalar($channels)) {
453
+ $channels = array($channels);
454
+ }
455
+
456
+ if(!$restObj) {
457
+ $restObj = new Mage_Connect_Rest($configObj->protocol);
458
+ }
459
+
460
+ $updates = array();
461
+ foreach($channels as $chan) {
462
+
463
+ if(!$cacheObject->isChannel($chan)) {
464
+ continue;
465
+ }
466
+ $chanName = $cacheObject->chanName($chan);
467
+ $localPackages = $cacheObject->getInstalledPackages($chanName);
468
+ $localPackages = $localPackages[$chanName];
469
+
470
+ if(!count($localPackages)) {
471
+ continue;
472
+ }
473
+
474
+ $channel = $cacheObject->getChannel($chan);
475
+ $uri = $channel[Mage_Connect_Singleconfig::K_URI];
476
+ $restObj->setChannel($uri);
477
+ $remotePackages = $restObj->getPackagesHashed();
478
+
479
+ /**
480
+ * Iterate packages of channel $chan
481
+ */
482
+ $state = $configObj->preferred_state ? $configObj->preferred_state : "stable";
483
+
484
+ foreach($localPackages as $localName=>$localData) {
485
+ if(!isset($remotePackages[$localName])) {
486
+ continue;
487
+ }
488
+ $package = $remotePackages[$localName];
489
+ $neededToUpgrade = false;
490
+ $remoteVersion = $localVersion = trim($localData[Mage_Connect_Singleconfig::K_VER]);
491
+ foreach($package as $version => $s) {
492
+
493
+ if( $cacheObject->compareStabilities($s, $state) < 0 ) {
494
+ continue;
495
+ }
496
+
497
+ if(version_compare($version, $localVersion, ">")) {
498
+ $neededToUpgrade = true;
499
+ $remoteVersion = $version;
500
+ }
501
+
502
+ if($checkConflicts) {
503
+ $conflicts = $cacheObject->hasConflicts($chanName, $localName, $remoteVersion);
504
+ if(false !== $conflicts) {
505
+ $neededToUpgrade = false;
506
+ }
507
+ }
508
+ }
509
+ if(!$neededToUpgrade) {
510
+ continue;
511
+ }
512
+ if(!isset($updates[$chanName])) {
513
+ $updates[$chanName] = array();
514
+ }
515
+ $updates[$chanName][$localName] = array("from"=>$localVersion, "to"=>$remoteVersion);
516
+ }
517
+ }
518
+ return $updates;
519
+ }
520
+
521
+ /**
522
+ * Get uninstall list
523
+ * @param string $chanName
524
+ * @param string $package
525
+ * @param Mage_Connect_Singleconfig $cache
526
+ * @param Mage_Connect_Config $config
527
+ * @param bool $withDepsRecursive
528
+ * @return array
529
+ */
530
+ public function getUninstallList($chanName, $package, $cache, $config, $withDepsRecursive = true)
531
+ {
532
+ static $level = 0;
533
+ static $hash = array();
534
+
535
+ $chanName = $cache->chanName($chanName);
536
+ $keyOuter = $chanName . "/" . $package;
537
+ $level++;
538
+
539
+ try {
540
+ $chanName = $cache->chanName($chanName);
541
+ if(!$cache->hasPackage($chanName, $package)) {
542
+ $level--;
543
+ if($level == 0) {
544
+ $hash = array();
545
+ return array('list'=>array());
546
+ }
547
+ return;
548
+ }
549
+ $dependencies = $cache->getPackageDependencies($chanName, $package);
550
+ $data = $cache->getPackage($chanName, $package);
551
+ $version = $data['version'];
552
+ $keyOuter = $chanName . "/" . $package;
553
+
554
+ //print "Processing outer: {$keyOuter} \n";
555
+ $hash[$keyOuter] = array (
556
+ 'name' => $package,
557
+ 'channel' => $chanName,
558
+ 'version' => $version,
559
+ 'packages' => $dependencies,
560
+ );
561
+
562
+ if($withDepsRecursive) {
563
+ $flds = array('name','channel','min','max');
564
+ $fldsCount = count($flds);
565
+ foreach($dependencies as $row) {
566
+ foreach($flds as $key) {
567
+ $varName = "p".ucfirst($key);
568
+ $$varName = $row[$key];
569
+ }
570
+ $method = __FUNCTION__;
571
+ $keyInner = $pChannel . "/" . $pName;
572
+ if(!isset($hash[$keyInner])) {
573
+ $this->$method($pChannel, $pName, $cache, $config,
574
+ $withDepsRecursive, false);
575
+ }
576
+ }
577
+ }
578
+
579
+ } catch (Exception $e) {
580
+ // $this->_failed[] = array(
581
+ // 'name'=>$package,
582
+ // 'channel'=>$chanName,
583
+ // 'max'=>$versionMax,
584
+ // 'min'=>$versionMin,
585
+ // 'reason'=>$e->getMessage()
586
+ // );
587
+ }
588
+
589
+ $level--;
590
+ if(0 === $level) {
591
+ $out = $this->processDepsHash($hash);
592
+ $hash = array();
593
+ return array('list'=>$out);
594
+ }
595
+ }
596
+
597
+ /**
598
+ * Add data to package dependencies hash array
599
+ * @param array $hash Package dependencies hash array
600
+ * @param string $name Package name
601
+ * @param string $channel Package chaannel
602
+ * @param string $downloaded_version Package downloaded version
603
+ * @param string $stability Package stability
604
+ * @param string $versionMin Required package minimum version
605
+ * @param string $versionMax Required package maximum version
606
+ * @param string $install_state Package install state
607
+ * @param string $message Package install message
608
+ * @param array $dependencies Package dependencies
609
+ */
610
+ private function addHashData(&$hash, $name, $channel, $downloaded_version = '', $stability = '', $versionMin = '',
611
+ $versionMax = '', $install_state = '', $message = '', $dependencies = '')
612
+ {
613
+ /**
614
+ * @todo When we are building dependencies tree we should base this calculations not on full key as on a
615
+ * unique value but check it by parts. First part which should be checked is EXTENSION_NAME also this
616
+ * part should be unique globally not per channel.
617
+ */
618
+ //$key = $chanName . "/" . $package;
619
+ $key = $name;
620
+ $hash[$key] = array (
621
+ 'name' => $name,
622
+ 'channel' => $channel,
623
+ 'downloaded_version' => $downloaded_version,
624
+ 'stability' => $stability,
625
+ 'min' => $versionMin,
626
+ 'max' => $versionMax,
627
+ 'install_state' => $install_state,
628
+ 'message' => (isset($this->install_states[$install_state]) ?
629
+ $this->install_states[$install_state] : '').$message,
630
+ 'packages' => $dependencies,
631
+ );
632
+
633
+ return true;
634
+ }
635
+
636
+ /**
637
+ * Get dependencies list/install order info
638
+ *
639
+ *
640
+ * @param string $chanName
641
+ * @param string $package
642
+ * @param Mage_Connect_Singleconfig $cache
643
+ * @param Mage_Connect_Config $config
644
+ * @param mixed $versionMax
645
+ * @param mixed $versionMin
646
+ * @param boolean $withDepsRecursive
647
+ * @param boolean $forceRemote
648
+ * @param Mage_Connect_Rest $rest
649
+ * @return mixed
650
+ */
651
+ public function getDependenciesList( $chanName, $package, $cache, $config, $versionMax = false, $versionMin = false,
652
+ $withDepsRecursive = true, $forceRemote = false, $rest = null)
653
+ {
654
+
655
+ static $level = 0;
656
+ static $_depsHash = array();
657
+ static $_deps = array();
658
+ static $_failed = array();
659
+ $install_state = 'install';
660
+ $version = '';
661
+ $stability = '';
662
+ $message = '';
663
+ $dependencies = array();
664
+
665
+ $level++;
666
+
667
+ try {
668
+ $chanName = $cache->chanName($chanName);
669
+
670
+ if (!$rest){
671
+ $rest = new Mage_Connect_Rest($config->protocol);
672
+ }
673
+ $rest->setChannel($cache->chanUrl($chanName));
674
+ $releases = $rest->getReleases($package);
675
+ if (!$releases || !count($releases)) {
676
+ throw new Exception("No releases for '{$package}', skipping");
677
+ }
678
+ $state = $config->preferred_state ? $config->preferred_state : 'stable';
679
+ /**
680
+ * Check current package version first
681
+ */
682
+ $installedPackage = $cache->getPackage($chanName, $package);
683
+ if ($installedPackage && is_array($installedPackage)) {
684
+ $installedRelease = array(array(
685
+ 'v' => $installedPackage['version'],
686
+ 's' => $installedPackage['stability'],
687
+ ));
688
+ $version = $cache->detectVersionFromRestArray($installedRelease, $versionMin, $versionMax, $state);
689
+ }
690
+ if (!$version) {
691
+ $version = $cache->detectVersionFromRestArray($releases, $versionMin, $versionMax, $state);
692
+ }
693
+ if (!$version) {
694
+ $versionState = $cache->detectVersionFromRestArray($releases, $versionMin, $versionMax);
695
+ if ($versionState) {
696
+ $packageInfo = $rest->getPackageReleaseInfo($package, $versionState);
697
+ if (false !== $packageInfo) {
698
+ $stability = $packageInfo->getStability();
699
+ throw new Exception("Extension is '{$stability}' please check(or change) stability settings".
700
+ " on Magento Connect Manager");
701
+ }
702
+ }
703
+ throw new Exception("Version for '{$package}' was not detected");
704
+ }
705
+ $packageInfo = $rest->getPackageReleaseInfo($package, $version);
706
+ if (false === $packageInfo) {
707
+ throw new Exception("Package release '{$package}' not found on server");
708
+ }
709
+ $stability = $packageInfo->getStability();
710
+
711
+ /**
712
+ * @todo check is package already installed
713
+ */
714
+ if ($installedPackage = $cache->isPackageInstalled($package)) {
715
+ if ($chanName == $installedPackage['channel']){
716
+ /**
717
+ * @todo check versions!!!
718
+ */
719
+ if (version_compare($version, $installedPackage['version'], '>')) {
720
+ $install_state = 'upgrade';
721
+ } elseif (version_compare($version, $installedPackage['version'], '<')) {
722
+ $version = $installedPackage['version'];
723
+ $stability = $installedPackage['stability'];
724
+ $install_state = 'wrong_version';
725
+ } else {
726
+ $install_state = 'already_installed';
727
+ }
728
+ } else {
729
+ $install_state = 'incompatible';
730
+ }
731
+ }
732
+
733
+ $deps_tmp = $packageInfo->getDependencyPackages();
734
+
735
+ /**
736
+ * @todo Select distinct packages grouped by name
737
+ */
738
+ $dependencies = array();
739
+ foreach ($deps_tmp as $row) {
740
+ if (isset($dependencies[$row['name']])) {
741
+ if ($installedPackageDep = $cache->isPackageInstalled($row['name'])) {
742
+ if ($installedPackageDep['channel'] == $row['channel']) {
743
+ $dependencies[$row['name']]=$row;
744
+ }
745
+ } elseif ($config->root_channel == $row['channel']) {
746
+ $dependencies[$row['name']] = $row;
747
+ }
748
+ } else {
749
+ $dependencies[$row['name']] = $row;
750
+ }
751
+ }
752
+
753
+ /**
754
+ * @todo When we are building dependencies tree we should base this calculations not on full key as on a
755
+ * unique value but check it by parts. First part which should be checked is EXTENSION_NAME also this part
756
+ * should be unique globally not per channel.
757
+ */
758
+ // $keyOuter = $chanName . "/" . $package;
759
+ $keyOuter = $package;
760
+
761
+ $this->addHashData($_depsHash, $package, $chanName, $version, $stability, $versionMin,
762
+ $versionMax, $install_state, $message, $dependencies);
763
+
764
+ if ($withDepsRecursive && 'incompatible' != $install_state) {
765
+ $flds = array('name','channel','min','max');
766
+ $fldsCount = count($flds);
767
+ foreach($dependencies as $row) {
768
+ foreach($flds as $key) {
769
+ $varName = "p".ucfirst($key);
770
+ $$varName = $row[$key];
771
+ }
772
+ $method = __FUNCTION__;
773
+ /**
774
+ * @todo When we are building dependencies tree we should base this calculations not on full key as
775
+ * on a unique value but check it by parts. First part which should be checked is EXTENSION_NAME
776
+ * also this part should be unique globally not per channel.
777
+ */
778
+ //$keyInner = $pChannel . "/" . $pName;
779
+ $keyInner = $pName;
780
+ if(!isset($_depsHash[$keyInner])) {
781
+ $_deps[] = $row;
782
+ $this->$method($pChannel, $pName, $cache, $config,
783
+ $pMax, $pMin, $withDepsRecursive, $forceRemote, $rest);
784
+ } else {
785
+ $downloaded = $_depsHash[$keyInner]['downloaded_version'];
786
+ $hasMin = $_depsHash[$keyInner]['min'];
787
+ $hasMax = $_depsHash[$keyInner]['max'];
788
+ if($pMin === $hasMin && $pMax === $hasMax) {
789
+ //var_dump("Equal requirements, skipping");
790
+ continue;
791
+ }
792
+
793
+ if($cache->versionInRange($downloaded, $pMin, $pMax)) {
794
+ //var_dump("Downloaded package matches new range too");
795
+ continue;
796
+ }
797
+
798
+ $names = array("pMin","pMax","hasMin","hasMax");
799
+ for($i=0, $c=count($names); $i<$c; $i++) {
800
+ if(!isset($$names[$i])) {
801
+ continue;
802
+ }
803
+ if(false !== $$names[$i]) {
804
+ continue;
805
+ }
806
+ $$names[$i] = $i % 2 == 0 ? "0" : "999999999";
807
+ }
808
+
809
+ if(!$cache->hasVersionRangeIntersect($pMin,$pMax, $hasMin, $hasMax)) {
810
+ $reason = "Detected {$pName} conflict of versions: {$hasMin}-{$hasMax} and {$pMin}-{$pMax}";
811
+ unset($_depsHash[$keyInner]);
812
+ $_failed[] = array(
813
+ 'name'=>$pName,
814
+ 'channel'=>$pChannel,
815
+ 'max'=>$pMax,
816
+ 'min'=>$pMin,
817
+ 'reason'=>$reason
818
+ );
819
+ continue;
820
+ }
821
+ $newMaxIsLess = version_compare($pMax, $hasMax, "<");
822
+ $newMinIsGreater = version_compare($pMin, $hasMin, ">");
823
+ $forceMax = $newMaxIsLess ? $pMax : $hasMax;
824
+ $forceMin = $newMinIsGreater ? $pMin : $hasMin;
825
+ //var_dump("Trying to process {$pName} : max {$forceMax} - min {$forceMin}");
826
+ $this->$method($pChannel, $pName, $cache, $config,
827
+ $forceMax, $forceMin, $withDepsRecursive, $forceRemote, $rest);
828
+ }
829
+ }
830
+ }
831
+ unset($rest);
832
+ } catch (Exception $e) {
833
+ $_failed[] = array(
834
+ 'name'=>$package,
835
+ 'channel'=>$chanName,
836
+ 'max'=>$versionMax,
837
+ 'min'=>$versionMin,
838
+ 'reason'=>$e->getMessage()
839
+ );
840
+ }
841
+
842
+
843
+ $level--;
844
+ if($level == 0) {
845
+ $out = $this->processDepsHash($_depsHash, false);
846
+ $deps = $_deps;
847
+ $failed = $_failed;
848
+ $_depsHash = array();
849
+ $_deps = array();
850
+ $_failed = array();
851
+ return array('deps' => $deps, 'result' => $out, 'failed'=> $failed);
852
+ }
853
+
854
+ }
855
+
856
+
857
+ /**
858
+ * Process dependencies hash
859
+ * Makes topological sorting and gives operation order list
860
+ *
861
+ * @param array $depsHash
862
+ * @param bool $sortReverse
863
+ * @return array
864
+ */
865
+ protected function processDepsHash(&$depsHash, $sortReverse = true)
866
+ {
867
+ $nodes = array();
868
+ $graph = new Mage_Connect_Structures_Graph();
869
+
870
+ foreach($depsHash as $key=>$data) {
871
+ $packages = $data['packages'];
872
+ $node = new Mage_Connect_Structures_Node();
873
+ $nodes[$key] =& $node;
874
+ unset($data['packages']);
875
+ $node->setData($data);
876
+ $graph->addNode($node);
877
+ unset($node);
878
+ }
879
+
880
+ if(count($nodes) > 1) {
881
+ foreach($depsHash as $key=>$data) {
882
+ $packages = $data['packages'];
883
+ foreach($packages as $pdata) {
884
+ $pName = $pdata['name'];
885
+ if(isset($nodes[$key], $nodes[$pName])) {
886
+ $nodes[$key]->connectTo($nodes[$pName]);
887
+ }
888
+ }
889
+ }
890
+ }
891
+
892
+ if (!$graph->isAcyclic()) {
893
+ throw new Exception("Dependency references are cyclic");
894
+ }
895
+
896
+ $result = $graph->topologicalSort();
897
+ $sortReverse ? krsort($result) : ksort($result);
898
+ $out = array();
899
+ $total = 0;
900
+ foreach($result as $order=>$nodes) {
901
+ foreach($nodes as $n) {
902
+ $out[] = $n->getData();
903
+ }
904
+ }
905
+ unset($graph, $nodes);
906
+ return $out;
907
+ }
908
+
909
+ }
downloader/lib/Mage/Connect/Repository.php ADDED
@@ -0,0 +1 @@
 
1
+
downloader/lib/Mage/Connect/Repository/Abstract.php ADDED
@@ -0,0 +1 @@
 
1
+
downloader/lib/Mage/Connect/Repository/Channel.php ADDED
@@ -0,0 +1 @@
 
1
+
downloader/lib/Mage/Connect/Repository/Channel/Abstract.php ADDED
@@ -0,0 +1 @@
 
1
+
downloader/lib/Mage/Connect/Repository/Channel/Commercial.php ADDED
@@ -0,0 +1 @@
 
1
+
downloader/lib/Mage/Connect/Repository/Channel/Community.php ADDED
@@ -0,0 +1 @@
 
1
+
downloader/lib/Mage/Connect/Repository/Channel/Core.php ADDED
@@ -0,0 +1 @@
 
1
+
downloader/lib/Mage/Connect/Repository/Local.php ADDED
@@ -0,0 +1 @@
 
1
+
downloader/lib/Mage/Connect/Rest.php ADDED
@@ -0,0 +1,366 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to work with remote REST interface
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+
35
+ class Mage_Connect_Rest
36
+ {
37
+
38
+ const CHANNELS_XML = "channels.xml";
39
+ const CHANNEL_XML = "channel.xml";
40
+ const PACKAGES_XML = "packages.xml";
41
+ const RELEASES_XML = "releases.xml";
42
+ const PACKAGE_XML = "package.xml";
43
+ const EXT = "tgz";
44
+
45
+ /**
46
+ * HTTP Loader
47
+ * @var Mage_HTTP_IClient
48
+ */
49
+ protected $_loader = null;
50
+
51
+
52
+ /**
53
+ * XML parser
54
+ * @var Mage_Xml_Parser
55
+ */
56
+ protected $_parser = null;
57
+
58
+ /**
59
+ * Channel URI
60
+ * @var string
61
+ */
62
+ protected $_chanUri = '';
63
+
64
+ /**
65
+ * Protocol HTTP or FTP
66
+ *
67
+ * @var string http or ftp
68
+ */
69
+ protected $_protocol = '';
70
+
71
+ /**
72
+ * Constructor
73
+ */
74
+ public function __construct($protocol="http")
75
+ {
76
+ switch ($protocol) {
77
+ case 'ftp':
78
+ $this->_protocol = 'ftp';
79
+ break;
80
+ case 'http':
81
+ $this->_protocol = 'http';
82
+ break;
83
+ default:
84
+ $this->_protocol = 'http';
85
+ break;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Set channel info
91
+ *
92
+ * @param string $uri
93
+ * @param sting $name
94
+ */
95
+ public function setChannel($uri)
96
+ {
97
+ $this->_chanUri = $uri;
98
+ }
99
+
100
+ /**
101
+ * Get HTTP loader
102
+ * @return Mage_Connect_Loader
103
+ */
104
+ public function getLoader()
105
+ {
106
+ if(is_null($this->_loader)) {
107
+ $this->_loader = Mage_Connect_Loader::getInstance($this->_protocol);
108
+ }
109
+ return $this->_loader;
110
+ }
111
+
112
+
113
+ /**
114
+ * Get parser
115
+ *
116
+ * @return Mage_Xml_Parser
117
+ */
118
+ protected function getParser()
119
+ {
120
+ if(is_null($this->_parser)) {
121
+ $this->_parser = new Mage_Xml_Parser();
122
+ }
123
+ return $this->_parser;
124
+ }
125
+
126
+ /**
127
+ * Load URI response
128
+ * @param string $uri
129
+ */
130
+ protected function loadChannelUri($uriSuffix)
131
+ {
132
+ $url = $this->_chanUri."/".$uriSuffix;
133
+ //print $url."\n";
134
+ $this->getLoader()->get($url);
135
+ $statusCode = $this->getLoader()->getStatus();
136
+ if($statusCode != 200) {
137
+ return false;
138
+ }
139
+ return $this->getLoader()->getBody();
140
+ }
141
+
142
+ /**
143
+ * Get channels list of URI
144
+ * @return array
145
+ */
146
+ public function getChannelInfo()
147
+ {
148
+ $out = $this->loadChannelUri(self::CHANNEL_XML);
149
+ $statusCode = $this->getLoader()->getStatus();
150
+ if($statusCode != 200) {
151
+ throw new Exception("Invalid server response for {$this->_chanUri}");
152
+ }
153
+ $parser = $this->getParser();
154
+ $out = $parser->loadXML($out)->xmlToArray();
155
+
156
+ // TODO: add channel validator
157
+ $vo = new Mage_Connect_Channel_VO();
158
+ $vo->fromArray($out['channel']);
159
+ if(!$vo->validate()) {
160
+ throw new Exception("Invalid channel.xml file");
161
+ }
162
+ return $vo;
163
+ }
164
+
165
+
166
+ /**
167
+ * Get packages list of channel
168
+ * @return array
169
+ */
170
+ public function getPackages()
171
+ {
172
+ $out = $this->loadChannelUri(self::PACKAGES_XML);
173
+ $statusCode = $this->getLoader()->getStatus();
174
+ if($statusCode != 200) {
175
+ return false;
176
+ }
177
+ $parser = $this->getParser();
178
+ $out = $parser->loadXML($out)->xmlToArray();
179
+
180
+
181
+ if(!isset($out['data']['p'])) {
182
+ return array();
183
+ }
184
+ if(isset($out['data']['p'][0])) {
185
+ return $out['data']['p'];
186
+ }
187
+ if(is_array($out['data']['p'])) {
188
+ return array($out['data']['p']);
189
+ }
190
+ return array();
191
+ }
192
+
193
+
194
+ public function getPackagesHashed()
195
+ {
196
+ $out = $this->loadChannelUri(self::PACKAGES_XML);
197
+ $statusCode = $this->getLoader()->getStatus();
198
+ if($statusCode != 200) {
199
+ return false;
200
+ }
201
+ $parser = $this->getParser();
202
+ $out = $parser->loadXML($out)->xmlToArray();
203
+
204
+ $return = array();
205
+ if(!isset($out['data']['p'])) {
206
+ return $return;
207
+ }
208
+ if(isset($out['data']['p'][0])) {
209
+ $return = $out['data']['p'];
210
+ }elseif(is_array($out['data']['p'])) {
211
+ $return = array($out['data']['p']);
212
+ }
213
+ $c = count($return);
214
+ if($c) {
215
+ $output = array();
216
+ for($i=0; $i<$c; $i++) {
217
+ $element = $return[$i];
218
+ $output[$element['n']] = $element['r'];
219
+ }
220
+ $return = $output;
221
+ }
222
+
223
+ $out = array();
224
+ foreach($return as $name=>$package) {
225
+ $stabilities = array_map(array($this, 'shortStateToLong'), array_keys($package));
226
+ $versions = array_map('trim', array_values($package));
227
+ $package = array_combine($versions, $stabilities);
228
+ ksort($package);
229
+ $out[$name] = $package;
230
+ }
231
+ return $out;
232
+ }
233
+
234
+ /**
235
+ * Stub
236
+ * @param $n
237
+ * @return unknown_type
238
+ */
239
+ public function escapePackageName($n)
240
+ {
241
+ return $n;
242
+ }
243
+
244
+ /**
245
+ * Get releases list of package on current channel
246
+ * @param string $package package name
247
+ */
248
+ public function getReleases($package)
249
+ {
250
+ $out = $this->loadChannelUri($this->escapePackageName($package)."/".self::RELEASES_XML);
251
+ $statusCode = $this->getLoader()->getStatus();
252
+ if($statusCode != 200) {
253
+ return false;
254
+ }
255
+ $parser = $this->getParser();
256
+ $out = $parser->loadXML($out)->xmlToArray();
257
+ if(!isset($out['releases']['r'])) {
258
+ return array();
259
+ }
260
+ $src = $out['releases']['r'];
261
+ if(!array_key_exists(0, $src)) {
262
+ return array($src);
263
+ }
264
+ $this->sortReleases($src);
265
+ return $src;
266
+ }
267
+
268
+ /**
269
+ * Sort releases
270
+ * @param array $releases
271
+ * @return void
272
+ */
273
+ public function sortReleases(array &$releases)
274
+ {
275
+ usort($releases, array($this, 'sortReleasesCallback'));
276
+ $releases = array_reverse($releases);
277
+ }
278
+
279
+ /**
280
+ * Sort releases callback
281
+ * @param string $a
282
+ * @param srting $b
283
+ * @return int
284
+ */
285
+ protected function sortReleasesCallback($a, $b)
286
+ {
287
+ return version_compare($a['v'],$b['v']);
288
+ }
289
+
290
+ /**
291
+ * Get package info (package.xml)
292
+ *
293
+ * @param $package
294
+ * @return unknown_type
295
+ */
296
+ public function getPackageInfo($package)
297
+ {
298
+ $out = $this->loadChannelUri($this->escapePackageName($package)."/".self::PACKAGE_XML);
299
+ if(false === $out) {
300
+ return false;
301
+ }
302
+ return new Mage_Connect_Package($out);
303
+ }
304
+
305
+ /**
306
+ *
307
+ * @param $package
308
+ * @param $version
309
+ * @return Mage_Connect_Package
310
+ */
311
+ public function getPackageReleaseInfo($package, $version)
312
+ {
313
+ $out = $this->loadChannelUri($this->escapePackageName($package)."/".$version."/".self::PACKAGE_XML);
314
+ if(false === $out) {
315
+ return false;
316
+ }
317
+ return new Mage_Connect_Package($out);
318
+ }
319
+
320
+ /**
321
+ * Get package archive file of release
322
+ * @param string $package package name
323
+ * @param string $version version
324
+ */
325
+ public function downloadPackageFileOfRelease($package, $version, $targetFile)
326
+ {
327
+ $package = $this->escapePackageName($package);
328
+ $version = $this->escapePackageName($version);
329
+
330
+
331
+ if(file_exists($targetFile)) {
332
+ $chksum = $this->loadChannelUri($package."/".$version."/checksum");
333
+ $statusCode = $this->getLoader()->getStatus();
334
+ if($statusCode == 200) {
335
+ if(md5_file($targetFile) == $chksum) {
336
+ return true;
337
+ }
338
+ }
339
+ }
340
+
341
+
342
+ $out = $this->loadChannelUri($package."/".$version."/".$package."-".$version.".".self::EXT);
343
+
344
+ $statusCode = $this->getLoader()->getStatus();
345
+ if($statusCode != 200) {
346
+ throw new Exception("Package not found: {$package} {$version}");
347
+ }
348
+ $dir = dirname($targetFile);
349
+ @mkdir($dir, 0777, true);
350
+ $result = @file_put_contents($targetFile, $out);
351
+ if(false === $result) {
352
+ throw new Exception("Cannot write to file {$targetFile}");
353
+ }
354
+ return true;
355
+ }
356
+
357
+ protected $states = array('b'=>'beta', 'd'=>'dev', 's'=>'stable', 'a'=>'alpha');
358
+
359
+ public function shortStateToLong($s)
360
+ {
361
+ return isset($this->states[$s]) ? $this->states[$s] : 'dev';
362
+ }
363
+
364
+
365
+ }
366
+
downloader/lib/Mage/Connect/Singleconfig.php ADDED
@@ -0,0 +1,934 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to manipulate with channel/package cache file
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+
35
+ class Mage_Connect_Singleconfig
36
+ {
37
+ /**
38
+ * Default single config filename
39
+ * 'cache.cfg'
40
+ */
41
+ const DEFAULT_SCONFIG_FILENAME = 'cache.cfg';
42
+
43
+ /**
44
+ * Cache data
45
+ * @var array
46
+ */
47
+ protected $_data = array();
48
+
49
+ /**
50
+ * Filename
51
+ * @var string
52
+ */
53
+ protected $_readFilename = false;
54
+
55
+ /**
56
+ *
57
+ * @var unknown_type
58
+ */
59
+ protected $_debug = false;
60
+
61
+ /**
62
+ *
63
+ * @var unknown_type
64
+ */
65
+ protected $_validator;
66
+
67
+ /**
68
+ * Internal keys constants
69
+ */
70
+ const K_CHAN = 'channels_by_name';
71
+ const K_CHAN_URI = 'channels_by_uri';
72
+ const K_CHAN_ALIAS = 'channel_aliases';
73
+ const K_PACK = 'packages';
74
+ const K_URI = 'uri';
75
+ const K_CHAN_DATA = 'channel_data';
76
+ const K_NAME = 'name';
77
+ const K_VER = 'version';
78
+ const K_STATE = 'stability';
79
+ const K_XML = 'xml';
80
+ const K_DEPS = 'deps';
81
+ const K_PACK_DEPS = 'pack_deps';
82
+ const K_CONFIG = 'config';
83
+
84
+ public function getValidUri($str)
85
+ {
86
+ $data = @parse_url($str);
87
+ if(isset($data['path'])) {
88
+ return $data['path'];
89
+ }
90
+ return false;
91
+ }
92
+
93
+ public function getFilename()
94
+ {
95
+ return $this->_readFilename;
96
+ }
97
+
98
+ public function formatUri($uri)
99
+ {
100
+ $uri = rtrim($uri, "/");
101
+ $uri = str_replace("http://", '', $uri);
102
+ $uri = str_replace("https://", '', $uri);
103
+ $uri = str_replace("ftp://", '', $uri);
104
+ return $uri;
105
+ }
106
+
107
+ /**
108
+ * Get data
109
+ * @return unknown_type
110
+ */
111
+ public function getData()
112
+ {
113
+ return $this->_data;
114
+ }
115
+
116
+ /**
117
+ * Constructor
118
+ * @param srting $file
119
+ * @return void
120
+ */
121
+ public function __construct($file = self::DEFAULT_SCONFIG_FILENAME)
122
+ {
123
+ $this->setEmptyConfig();
124
+ if($file) {
125
+ $this->_readFilename = $file;
126
+ $this->load();
127
+ }
128
+ }
129
+
130
+
131
+ /**
132
+ * Load cache from file
133
+ * @param string $file
134
+ * @return void
135
+ */
136
+ public function load($file = false)
137
+ {
138
+ if(false === $file) {
139
+ $file = $this->_readFilename;
140
+ }
141
+ if(false === $file) {
142
+ return;
143
+ }
144
+
145
+ if(!file_exists($file)||filesize($file)==0) {
146
+ $this->save($file);
147
+ return;
148
+ }
149
+
150
+ if(!is_readable($file)) {
151
+ return $this->doError("File is not readable: '{$file}'");
152
+ }
153
+
154
+ $this->_readFilename = $file;
155
+
156
+ $data = @file_get_contents($file);
157
+ if(false === $data) {
158
+ return $this->doError("Cannot get file contents: '{$file}'");
159
+ }
160
+
161
+ if(!$this->_debug) {
162
+ $data = @gzuncompress($data);
163
+ if(false === $data) {
164
+ return $this->doError("Cannot unpack gzipped data in file contents: '{$file}'");
165
+ }
166
+ }
167
+ $data = @unserialize($data);
168
+ if(unserialize(false) === $data) {
169
+ return $this->doError("Cannot unserialize data in file contents: '{$file}'");
170
+ }
171
+
172
+
173
+ $validData = true;
174
+ foreach(array_keys($this->_data) as $k) {
175
+ if(!isset($data[$k])) {
176
+ $validData = false;
177
+ } else {
178
+ $this->_data[$k] = $data[$k];
179
+ }
180
+ }
181
+ if($validData) {
182
+ $this->_data = $data;
183
+ } else {
184
+ $this->save();
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Save contents
190
+ * @param string $file
191
+ * @return void
192
+ */
193
+ public function save($file = false)
194
+ {
195
+ if(false === $file) {
196
+ $file = $this->_readFilename;
197
+ }
198
+ if(false === $file) {
199
+ return;
200
+ }
201
+ $data = @serialize($this->_data);
202
+ if(!$this->_debug) {
203
+ $data = @gzcompress($data);
204
+ }
205
+ $res=true;
206
+ if((!file_exists($file)&&is_writable(dirname($file)))||(file_exists($file)&&is_writable($file))){
207
+ $res = @file_put_contents($file, $data);
208
+ }
209
+ if(!$res) {
210
+ $this->doError("Cannot save: '{$file}'");
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Set empty config skeleton
216
+ * @return void
217
+ */
218
+ public function setEmptyConfig()
219
+ {
220
+ $this->_data = array(
221
+ self::K_CHAN => array (),
222
+ self::K_CHAN_URI => array (),
223
+ self::K_CHAN_ALIAS => array (),
224
+ );
225
+ }
226
+
227
+ /**
228
+ * Check channel, add if valid name and not exist
229
+ * @param string $chanName
230
+ * @param Mage_Connect_Config $config
231
+ * @param Mage_Connect_Rest $rest
232
+ * @return boolean
233
+ */
234
+ public function checkChannel($chanName, $config, $rest = null)
235
+ {
236
+ if ($this->isChannel($chanName)) {
237
+ return true;
238
+ }
239
+
240
+ $uri = '';
241
+
242
+ $_validator = new Mage_Connect_Validator();
243
+ if ($this->isChannelName($chanName)) {
244
+ $uri = $this->chanUrl($chanName);
245
+ } elseif ($_validator->validateUrl($chanName)) {
246
+ $uri = $chanName;
247
+ } elseif($chanName) {
248
+ $uri = $config->protocol.'://'.$chanName;
249
+ } else {
250
+ throw new Exception("'{$chanName}' is not existant channel name / valid uri");
251
+ }
252
+
253
+ if ($uri && !$this->isChannel($uri)) {
254
+ if (!isset($rest)) {
255
+ $rest = new Mage_Connect_Rest($config->protocol);
256
+ }
257
+ $rest->setChannel($uri);
258
+ $data = $rest->getChannelInfo();
259
+ $data->uri = $uri;
260
+ $this->addChannel($data->name, $uri);
261
+ }
262
+
263
+ return $this->isChannel($uri);
264
+ }
265
+
266
+ public function isChannel($chanName)
267
+ {
268
+ if($this->isChannelName($chanName)) {
269
+ return true;
270
+ }
271
+ if($this->isChannelUri($chanName)) {
272
+ return true;
273
+ }
274
+ if($this->isChannelAlias($chanName)) {
275
+ return true;
276
+ }
277
+ return false;
278
+ }
279
+
280
+ /**
281
+ * Get channel
282
+ * @param string $chanName
283
+ * @return array
284
+ */
285
+ public function getChannel($chanName)
286
+ {
287
+ if($this->isChannelAlias($chanName)) {
288
+ $chanName = $this->getChannelNameByAlias($chanName);
289
+ } elseif($this->isChannelUri($chanName)) {
290
+ $chanName = $this->getChannelUriRecord($chanName);
291
+ }
292
+ if($this->isChannelName($chanName)) {
293
+ return $this->_data[self::K_CHAN][$chanName];
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Is channel name?
299
+ * @param $chanName
300
+ * @return bool
301
+ */
302
+ public function isChannelName($chanName)
303
+ {
304
+ return isset($this->_data[self::K_CHAN][$chanName]);
305
+ }
306
+
307
+ /**
308
+ * Is channel alias?
309
+ * @param string $chanName
310
+ * @return bool
311
+ */
312
+ public function isChannelAlias($chanName)
313
+ {
314
+ return isset($this->_data[self::K_CHAN_ALIAS][$chanName]);
315
+ }
316
+
317
+ /**
318
+ * Is channel uri?
319
+ * @param $uri
320
+ * @return bool
321
+ */
322
+ public function isChannelUri($uri)
323
+ {
324
+ $uri = $this->formatUri($uri);
325
+ return isset($this->_data[self::K_CHAN_URI][$uri]);
326
+ }
327
+
328
+ /**
329
+ * Unset channel uri record
330
+ * @param string $uri
331
+ * @return void
332
+ */
333
+ protected function unsetChannelUriRecord($uri)
334
+ {
335
+ $uri = $this->formatUri($uri);
336
+ unset($this->_data[self::K_CHAN_URI][$uri]);
337
+ }
338
+
339
+ /**
340
+ * Set channel uri record: uri maps to channel record
341
+ * @param string $chanName
342
+ * @param string $uri
343
+ * @return void
344
+ */
345
+ protected function setChannelUriRecord($chanName, $uri)
346
+ {
347
+ $uri = $this->formatUri($uri);
348
+ $this->_data[self::K_CHAN_URI][$uri] = $chanName;
349
+ }
350
+
351
+ /**
352
+ * Get channel name by uri record
353
+ * @param string $uri
354
+ * @return string
355
+ */
356
+ protected function getChannelUriRecord($uri)
357
+ {
358
+ $uri = $this->formatUri($uri);
359
+ return $this->_data[self::K_CHAN_URI][$uri];
360
+ }
361
+
362
+
363
+ /**
364
+ * Unset channel record
365
+ * @param string $chanName
366
+ * @return void
367
+ */
368
+ protected function unsetChannelRecord($chanName)
369
+ {
370
+ unset($this->_data[self::K_CHAN][$chanName]);
371
+ }
372
+
373
+ /**
374
+ * Get channel record
375
+ * @param string $chanName
376
+ * @return array
377
+ */
378
+ protected function getChannelRecord($chanName)
379
+ {
380
+ return $this->_data[self::K_CHAN][$chanName];
381
+ }
382
+
383
+ /**
384
+ * Set channel record
385
+ * @param string $chanName
386
+ * @param string $uri
387
+ * @param mixed $data
388
+ * @param array $packages
389
+ * @return void
390
+ */
391
+ protected function setChannelRecord($chanName, $uri, $data, $packages = array())
392
+ {
393
+ $this->_data[self::K_CHAN][$chanName] = array(
394
+ self::K_NAME=>$chanName,
395
+ self::K_URI=>$uri,
396
+ self::K_CHAN_DATA=>$data,
397
+ self::K_PACK=>$packages
398
+ );
399
+ }
400
+
401
+ /**
402
+ * Set package record
403
+ * @param string $chanName
404
+ * @param string $packageName
405
+ * @param mixed $data
406
+ * @return void
407
+ */
408
+ protected function setPackageRecord($chanName, $packageName, $data, $oneField = null)
409
+ {
410
+ if(null === $oneField) {
411
+ $this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName] = $data;
412
+ } else {
413
+ $this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName][$oneField] = $data;
414
+ }
415
+ }
416
+
417
+
418
+
419
+ /**
420
+ * Unset package record
421
+ * @param string $chanName
422
+ * @param string $packageName
423
+ * @return void
424
+ */
425
+ protected function unsetPackageRecord($chanName, $packageName)
426
+ {
427
+ unset($this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName]);
428
+ }
429
+
430
+ /**
431
+ * Get package record
432
+ *
433
+ * @param string $chanName
434
+ * @param string $packageName
435
+ * @return array
436
+ */
437
+ protected function fetchPackage($chanName, $packageName, $field = null)
438
+ {
439
+ if(null === $field) {
440
+ return $this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName];
441
+ } else {
442
+ return $this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName][$field];
443
+ }
444
+ }
445
+
446
+ /**
447
+ * Has package record
448
+ * @param string $chanName
449
+ * @param string $packageName
450
+ * @return bool
451
+ */
452
+ protected function hasPackageRecord($chanName, $packageName)
453
+ {
454
+ return isset($this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName]);
455
+ }
456
+
457
+ /**
458
+ * Get channel name by alias
459
+ * @param string $alias
460
+ * @return array
461
+ */
462
+ protected function getChannelNameByAlias($alias)
463
+ {
464
+ return $this->_data[self::K_CHAN_ALIAS][$alias];
465
+ }
466
+
467
+ /**
468
+ * Set channel alias
469
+ * @param string $alias
470
+ * @param string $chanName
471
+ * @return void
472
+ */
473
+ protected function setChannelAlias($alias, $chanName)
474
+ {
475
+ $this->_data[self::K_CHAN_ALIAS][$alias] = $chanName;
476
+ }
477
+
478
+ /**
479
+ * Unset channel alias
480
+ * @param string $alias
481
+ * @return void
482
+ */
483
+ protected function unsetChannelAlias($alias)
484
+ {
485
+ unset($this->_data[self::K_CHAN_ALIAS][$alias]);
486
+ }
487
+
488
+ /**
489
+ * Clear all aliases of channel
490
+ * @param string $chanName channel name
491
+ * @return void
492
+ */
493
+ protected function clearAliases($chanName)
494
+ {
495
+ $keys = array_keys($this->_data[self::K_CHAN_ALIAS]);
496
+ foreach ($keys as $key) {
497
+ if($this->_data[self::K_CHAN_ALIAS][$key] == $chanName) {
498
+ unset($this->_data[self::K_CHAN_ALIAS][$key]);
499
+ }
500
+ }
501
+ }
502
+
503
+ /**
504
+ * Add channel alias
505
+ * @param string $chanName
506
+ * @param string $alias
507
+ * @return void
508
+ */
509
+ public function addChannelAlias($chanName, $alias)
510
+ {
511
+ if($this->isChannelName($alias)) {
512
+ return $this->doError("Alias '{$alias}' is existant channel name!");
513
+ }
514
+
515
+ if(!$this->isChannelName($chanName)) {
516
+ return $this->doError("Channel '{$chanName}' doesn't exist");
517
+ }
518
+ $this->setChannelAlias($alias, $chanName);
519
+ $this->save();
520
+ }
521
+
522
+
523
+
524
+ /**
525
+ * Add channel
526
+ * @param $chanName
527
+ * @param $uri
528
+ * @param $data
529
+ * @return void
530
+ */
531
+ public function addChannel($chanName, $uri, $data = array())
532
+ {
533
+ if($this->isChannelName($chanName)) {
534
+ return $this->doError("Channel '{$chanName}' already exist!");
535
+ }
536
+ if($this->isChannelUri($uri)) {
537
+ return $this->doError("Channel with uri= '{$uri}' already exist!");
538
+ }
539
+ if($this->isChannelAlias($chanName)) {
540
+ $this->unsetChannelAlias($chanName);
541
+ }
542
+ $uri = $this->formatUri($uri);
543
+ $this->setChannelRecord($chanName, $uri, $data);
544
+ $this->setChannelUriRecord($chanName, $uri);
545
+ $this->save();
546
+ }
547
+
548
+
549
+
550
+ /**
551
+ * Delete channel
552
+ * @param $chanName
553
+ * @return void
554
+ */
555
+ public function deleteChannel($chanName)
556
+ {
557
+ if($this->isChannelName($chanName)) {
558
+ $record = $this->getChannelRecord($chanName);
559
+ $this->unsetChannelUriRecord($record[self::K_URI]);
560
+ $this->unsetChannelRecord($chanName);
561
+ $this->clearAliases($chanName);
562
+ } elseif($this->isChannelUri($chanName)) {
563
+ $uri = $chanName;
564
+ $chanName = $this->getChannelUriRecord($uri);
565
+ $this->unsetChannelUriRecord($uri);
566
+ $this->unsetChannelRecord($chanName);
567
+ $this->clearAliases($chanName);
568
+ } elseif($this->isChannelAlias($chanName)) {
569
+ $this->unsetChannelAlias($chanName);
570
+ } else {
571
+ return $this->doError("'{$chanName}' was not found in aliases, channel names, channel uris");
572
+ }
573
+ $this->save();
574
+ }
575
+
576
+
577
+ /**
578
+ * Converts channel name, url or alias to channel name
579
+ * throws exception if not found
580
+ * @param srting $chanName
581
+ * @return string
582
+ */
583
+ public function chanName($chanName)
584
+ {
585
+ $channelData = $this->getChannel($chanName);
586
+ if(!$channelData) {
587
+ return $this->doError("Channel '{$chanName}' doesn't exist");
588
+ }
589
+ return $channelData[self::K_NAME];
590
+ }
591
+
592
+ public function chanUrl($chan)
593
+ {
594
+ $channelData = $this->getChannel($chan);
595
+ if(!$channelData) {
596
+ return $this->doError("Channel '{$chan}' doesn't exist");
597
+ }
598
+ return $channelData[self::K_URI];
599
+ }
600
+
601
+
602
+ /**
603
+ * Add package
604
+ * @param Mage_Connect_Package $package
605
+ * @return void
606
+ */
607
+ public function addPackage($package)
608
+ {
609
+ $channel = $this->chanName($package->getChannel());
610
+ $name = $package->getName();
611
+ $record = array (
612
+ self::K_VER => $package->getVersion(),
613
+ self::K_STATE => $package->getStability(),
614
+ self::K_XML => $package->getPackageXml(),
615
+ self::K_NAME => $name,
616
+ self::K_DEPS => array(),
617
+ self::K_PACK_DEPS => array(),
618
+ );
619
+ $this->setPackageRecord($channel, $name, $record);
620
+ $this->setPackageDependencies($channel, $name, $package->getDependencyPackages());
621
+ $this->save();
622
+ }
623
+
624
+
625
+
626
+
627
+ /**
628
+ * Delete package
629
+ * @param string $chanName
630
+ * @param string $package
631
+ * @return void
632
+ */
633
+ public function deletePackage($chanName, $package)
634
+ {
635
+ $chanName = $this->chanName($chanName);
636
+ $this->unsetPackageRecord($chanName, $package);
637
+ $this->save();
638
+ }
639
+
640
+ /**
641
+ * Get package
642
+ * @param sting $chanName
643
+ * @param string $package
644
+ * @return void
645
+ */
646
+ public function getPackage($chanName, $package)
647
+ {
648
+ $chanName = $this->chanName($chanName);
649
+ if($this->hasPackageRecord($chanName, $package)) {
650
+ return $this->fetchPackage($chanName, $package);
651
+ }
652
+ return null;
653
+ }
654
+
655
+ public function getPackageObject($chanName, $package)
656
+ {
657
+ $chanName = $this->chanName($chanName);
658
+ if($this->hasPackageRecord($chanName, $package)) {
659
+ $data = $this->fetchPackage($chanName, $package);
660
+ return new Mage_Connect_Package($data[self::K_XML]);
661
+ }
662
+ throw new Exception("Cannot get package: '{$package}'");
663
+ }
664
+
665
+
666
+ public function hasPackage($chanName, $package, $versionMin = false, $versionMax = false)
667
+ {
668
+ $chanName = $this->chanName($chanName);
669
+ $data = $this->getPackage($chanName, $package);
670
+ if(null === $data) {
671
+ return false;
672
+ }
673
+ $installedVersion = $data[self::K_VER];
674
+ return $this->versionInRange($installedVersion, $versionMin, $versionMax);
675
+ }
676
+
677
+ /**
678
+ * Check whether package installed or not. Return package if it installed
679
+ *
680
+ * @param string $package package name
681
+ * @return array
682
+ */
683
+ public function isPackageInstalled($package)
684
+ {
685
+ $channels = $this->getChannelNames();
686
+ foreach ($channels as $channel) {
687
+ if ($installedPackage = $this->getPackage($channel, $package)) {
688
+ return array_merge(array('channel'=>$channel), $installedPackage);
689
+ }
690
+
691
+ }
692
+ return false;
693
+ }
694
+
695
+ /**
696
+ * Checks whether the version in in the specified range of versionMin to versionMax
697
+ *
698
+ * @param string $version
699
+ * @param string $versionMin
700
+ * @param string $versionMax
701
+ * @return bool
702
+ */
703
+ public function versionInRange($version, $versionMin = false, $versionMax = false)
704
+ {
705
+ if(false === $versionMin || empty($versionMin)) {
706
+ $minOk = true;
707
+ } else {
708
+ $minOk = version_compare($version, $versionMin, ">=");
709
+ }
710
+ if(false === $versionMax || empty($versionMax)) {
711
+ $maxOk = true;
712
+ } else {
713
+ $maxOk = version_compare($version, $versionMax, "<=");
714
+ }
715
+ return $minOk && $maxOk;
716
+ }
717
+
718
+ public function hasVersionRangeIntersect($min1, $max1, $min2, $max2)
719
+ {
720
+ if(version_compare($min1, $min2, ">") && version_compare($max1, $max2, ">")) {
721
+ return false;
722
+ } elseif(version_compare($min1, $min2, "<") && version_compare($max1, $max2, "<")) {
723
+ return false;
724
+ } elseif(version_compare($min1, $min2, ">=") && version_compare($max1, $max2, "<=")) {
725
+ return true;
726
+ } elseif(version_compare($min1, $min2, "<=") && version_compare($max1, $max2, ">=")) {
727
+ return true;
728
+ }
729
+ return false;
730
+ }
731
+
732
+ /**
733
+ * Clear contents to defaults and save
734
+ * @return void
735
+ */
736
+ public function clear()
737
+ {
738
+ $this->setEmptyConfig();
739
+ $this->save();
740
+ }
741
+
742
+ /**
743
+ * Output error - throw exception
744
+ * @param $message
745
+ * @throws Exception
746
+ * @return void
747
+ */
748
+ protected function doError($message)
749
+ {
750
+ throw new Exception($message);
751
+ }
752
+
753
+
754
+
755
+
756
+
757
+ public function compareStabilities($s1, $s2)
758
+ {
759
+ if(!$this->_validator) {
760
+ $this->_validator = new Mage_Connect_Validator();
761
+ }
762
+ return $this->_validator->compareStabilities($s1, $s2);
763
+ }
764
+
765
+
766
+
767
+ public function detectVersionFromRestArray($restData, $argVersionMin = false, $argVersionMax = false,
768
+ $preferredStability = 'devel')
769
+ {
770
+
771
+ if(!is_array($restData)) {
772
+ return false;
773
+ }
774
+
775
+ foreach($restData as $vData) {
776
+ $stability = trim($vData['s']);
777
+ $version = trim($vData['v']);
778
+ $goodStability = $this->compareStabilities($stability, $preferredStability) >= 0;
779
+ if($goodStability && $this->versionInRange($version, $argVersionMin, $argVersionMax)) {
780
+ return $version;
781
+ }
782
+ }
783
+ return false;
784
+ }
785
+
786
+
787
+ public function setPackageDependencies($chanName, $package, $data)
788
+ {
789
+ $chanName = $this->chanName($chanName);
790
+ if($this->hasPackageRecord($chanName, $package)) {
791
+ $this->setPackageRecord($chanName, $package, $data, self::K_PACK_DEPS);
792
+ $this->save();
793
+ return true;
794
+ }
795
+ return false;
796
+ }
797
+
798
+ public function getPackageDependencies($chanName, $package)
799
+ {
800
+ $chanName = $this->chanName($chanName);
801
+ if($this->hasPackageRecord($chanName, $package)) {
802
+ return $this->fetchPackage($chanName, $package, self::K_PACK_DEPS);
803
+ }
804
+ return false;
805
+ }
806
+
807
+
808
+
809
+ public function setDependencyInfo($chanName, $package, $data)
810
+ {
811
+ $chanName = $this->chanName($chanName);
812
+ if($this->hasPackageRecord($chanName, $package)) {
813
+ $this->setPackageRecord($chanName, $package, $data, self::K_DEPS);
814
+ $this->save();
815
+ return true;
816
+ }
817
+ return false;
818
+ }
819
+
820
+ public function getDependencyInfo($chanName, $package)
821
+ {
822
+ $chanName = $this->chanName($chanName);
823
+ if($this->hasPackageRecord($chanName, $package)) {
824
+ return $this->fetchPackage($chanName, $package, self::K_DEPS);
825
+ }
826
+ return false;
827
+ }
828
+
829
+ public function getChannelNames()
830
+ {
831
+ return array_keys($this->_data[self::K_CHAN]);
832
+ }
833
+
834
+ public function getPackagesData($channel = false)
835
+ {
836
+ if(false == $channel) {
837
+ return $this->_data[self::K_CHAN];
838
+ }
839
+
840
+ if(!$this->isChannel($channel)) {
841
+ return array();
842
+ }
843
+ return $this->getChannel($channel);
844
+ }
845
+
846
+ public function specifiedInDependencyList($deps, $chanName, $packageName)
847
+ {
848
+ foreach($deps as $dep) {
849
+ if($chanName == $dep['channel'] && $packageName == $dep['name']) {
850
+ return true;
851
+ }
852
+ }
853
+ return false;
854
+ }
855
+
856
+ public function requiredByOtherPackages($chanName, $packageName, $excludeList = array())
857
+ {
858
+ $out = array();
859
+ foreach($this->_data[self::K_CHAN] as $channel=>$data) {
860
+ foreach($data[self::K_PACK] as $package) {
861
+ if($this->specifiedInDependencyList($excludeList, $channel, $package['name'])) {
862
+ continue;
863
+ }
864
+ $deps = $package[self::K_PACK_DEPS];
865
+ if($this->specifiedInDependencyList($deps, $chanName, $packageName)) {
866
+ $out[] = array('channel'=>$channel, 'name' =>$package['name'], 'version'=>$package['version']);
867
+ }
868
+ }
869
+ }
870
+ return $out;
871
+ }
872
+
873
+ public function getInstalledPackages($chanName = false)
874
+ {
875
+ if(false == $chanName) {
876
+ $data = $this->getChannelNames();
877
+ } elseif($this->isChannel($chanName)) {
878
+ $tmp = $this->getChannel($chanName);
879
+ $data = array($tmp[self::K_NAME]);
880
+ }
881
+ $out = array();
882
+ foreach( $data as $chanName) {
883
+ $channel = $this->getChannel($chanName);
884
+ $out[$chanName] = array();
885
+ foreach($channel[self::K_PACK] as $package=>$data) {
886
+ $out[$chanName][$package] = array();
887
+ foreach(array(self::K_VER, self::K_STATE) as $k) {
888
+ $out[$chanName][$package][$k] = $data[$k];
889
+ }
890
+ }
891
+ }
892
+ return $out;
893
+ }
894
+
895
+ /**
896
+ * Check if package conflicts with installed packages
897
+ * Returns:
898
+ * array with conflicts
899
+ * false if no conflicts
900
+ *
901
+ * @param string $chanName
902
+ * @param string $packageName
903
+ * @param string $version
904
+ * @return array|false
905
+ */
906
+ public function hasConflicts($chanName, $packageName, $version)
907
+ {
908
+ $conflicts = array();
909
+ foreach($this->_data[self::K_CHAN] as $channel=>$data) {
910
+ foreach($data[self::K_PACK] as $package) {
911
+ /**
912
+ * @todo When we are building dependencies tree we should base this calculations not on full key as on
913
+ * a unique value but check it by parts. First part which should be checked is EXTENSION_NAME also this
914
+ * part should be unique globally not per channel.
915
+ */
916
+ /*if($channel != $chanName) {
917
+ continue;
918
+ }*/
919
+ $deps = $package[self::K_PACK_DEPS];
920
+ foreach($deps as $dep) {
921
+ if($dep['name'] != $packageName) {
922
+ continue;
923
+ }
924
+
925
+ if(!$this->versionInRange($version, $dep['min'], $dep['max'])) {
926
+ //var_dump($version, $dep['min'], $dep['max']);
927
+ $conflicts[] = $channel . "/". $package['name'] ." ". $package['version'];
928
+ }
929
+ }
930
+ }
931
+ }
932
+ return count($conflicts) ? $conflicts : false;
933
+ }
934
+ }
downloader/lib/Mage/Connect/Structures/Graph.php ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ class Mage_Connect_Structures_Graph
28
+ {
29
+ protected $_nodes = array();
30
+ protected $_directed = false;
31
+ protected $_nodeClassName = 'Mage_Connect_Structures_Node';
32
+
33
+ const ACYCLIC_VISITED_KEY = 'acyclic-test-visited';
34
+ const SORT_VISITED_KEY = 'topological-sort-visited';
35
+ const SORT_LEVEL_KEY = 'topological-sort-level';
36
+
37
+ /**
38
+ * Constructor
39
+ * @param bool $directed directed graph?
40
+ * @return void
41
+ */
42
+ public function __construct($directed = true)
43
+ {
44
+ $this->_directed = $directed;
45
+ }
46
+
47
+
48
+ /**
49
+ * Is graph directed?
50
+ *
51
+ * @return bool
52
+ */
53
+ public function isDirected()
54
+ {
55
+ return (boolean) $this->_directed;
56
+ }
57
+
58
+ /**
59
+ * Add node to list
60
+ *
61
+ * @param Mage_Connect_Structures_Graph_Node $newNode
62
+ * @return void
63
+ */
64
+ public function addNode(&$newNode)
65
+ {
66
+ if(!$newNode instanceof $this->_nodeClassName) {
67
+ throw new Exception(__METHOD__." : invalid node class, should be instance of: ".$this->_nodeClassName);
68
+ }
69
+ foreach($this->_nodes as $key => $node) {
70
+ if($newNode === $node) {
71
+ throw new Exception(__METHOD__." : received duplicate object");
72
+ }
73
+ }
74
+ $this->_nodes[] =& $newNode;
75
+ $newNode->setGraph($this);
76
+ }
77
+
78
+ /**
79
+ * Remove a Node from the Graph
80
+ * @param Mage_Connect_Structures_Graph_Node $node
81
+ */
82
+ public function removeNode(&$node)
83
+ {
84
+
85
+ }
86
+
87
+ /**
88
+ * Return set of nodes
89
+ * @return array
90
+ */
91
+ public function &getNodes()
92
+ {
93
+ return $this->_nodes;
94
+ }
95
+
96
+ /**
97
+ * Is asyclic
98
+ * @return unknown_type
99
+ */
100
+ public function isAcyclic()
101
+ {
102
+ if (!$this->isDirected()) {
103
+ return false;
104
+ }
105
+ return self::_isAcyclic($this);
106
+ }
107
+
108
+ /**
109
+ *
110
+ * This is a variant of Graph::inDegree which does
111
+ * not count nodes marked as visited.
112
+ *
113
+ * @return integer
114
+ */
115
+ protected static function _nonVisitedInDegree(&$node, $metadataKey)
116
+ {
117
+ $result = 0;
118
+ $graphNodes =& $node->getGraph()->getNodes();
119
+ foreach (array_keys($graphNodes) as $key) {
120
+ if ((!$graphNodes[$key]->getMetadata($metadataKey)) && $graphNodes[$key]->connectsTo($node)) {
121
+ $result++;
122
+ }
123
+ }
124
+ return $result;
125
+ }
126
+
127
+ /**
128
+ * Is graph acyclic?
129
+ * @param $graph
130
+ * @return bool
131
+ */
132
+ protected static function _isAcyclic(&$graph)
133
+ {
134
+ // Mark every node as not visited
135
+ $nodes =& $graph->getNodes();
136
+ $nodeKeys = array_keys($nodes);
137
+ $refGenerator = array();
138
+ foreach($nodeKeys as $key) {
139
+ $refGenerator[] = false;
140
+ $nodes[$key]->setMetadata(self::ACYCLIC_VISITED_KEY, $refGenerator[sizeof($refGenerator) - 1]);
141
+ }
142
+
143
+ // Iteratively peel off leaf nodes
144
+ do {
145
+ // Find out which nodes are leafs (excluding visited nodes)
146
+ $leafNodes = array();
147
+ foreach($nodeKeys as $key) {
148
+ if ((!$nodes[$key]->getMetadata(self::ACYCLIC_VISITED_KEY)) &&
149
+ self::_nonVisitedInDegree($nodes[$key], self::ACYCLIC_VISITED_KEY) == 0) {
150
+ $leafNodes[] =& $nodes[$key];
151
+ }
152
+ }
153
+ // Mark leafs as visited
154
+ for ($i=sizeof($leafNodes) - 1; $i>=0; $i--) {
155
+ $visited =& $leafNodes[$i]->getMetadata(self::ACYCLIC_VISITED_KEY);
156
+ $visited = true;
157
+ $leafNodes[$i]->setMetadata(self::ACYCLIC_VISITED_KEY, $visited);
158
+ }
159
+ } while (sizeof($leafNodes) > 0);
160
+
161
+
162
+ // If graph is a DAG, there should be no non-visited nodes.
163
+ // Let's try to prove otherwise
164
+ $result = true;
165
+ foreach($nodeKeys as $key) {
166
+ if (!$nodes[$key]->getMetadata(self::ACYCLIC_VISITED_KEY)) {
167
+ $result = false;
168
+ break;
169
+ }
170
+ }
171
+
172
+ // Cleanup visited marks
173
+ foreach($nodeKeys as $key) {
174
+ $nodes[$key]->unsetMetadata(self::ACYCLIC_VISITED_KEY);
175
+ }
176
+
177
+ return $result;
178
+ }
179
+
180
+ /**
181
+ *
182
+ * sort returns the graph's nodes, sorted by topological order.
183
+ *
184
+ * The result is an array with
185
+ * as many entries as topological levels.
186
+ *
187
+ * Each entry in this array is an array of nodes within
188
+ * the given topological level.
189
+ *
190
+ * @return array
191
+ */
192
+ public function topologicalSort()
193
+ {
194
+ // We only sort graphs
195
+ self::_topologicalSort($this);
196
+ $result = array();
197
+ // Fill out result array
198
+ $nodes =& $this->getNodes();
199
+ $nodeKeys = array_keys($nodes);
200
+ foreach($nodeKeys as $key) {
201
+ $k = $nodes[$key]->getMetadata(self::SORT_LEVEL_KEY);
202
+ if (!array_key_exists($k, $result)) {
203
+ $result[$k] = array();
204
+ }
205
+ $result[$k][] =& $nodes[$key];
206
+ $nodes[$key]->unsetMetadata(self::SORT_LEVEL_KEY);
207
+ }
208
+ return $result;
209
+ }
210
+
211
+ protected static function _topologicalSort(&$graph)
212
+ {
213
+ // Mark every node as not visited
214
+ $nodes =& $graph->getNodes();
215
+ $nodeKeys = array_keys($nodes);
216
+ $refGenerator = array();
217
+ foreach($nodeKeys as $key) {
218
+ $refGenerator[] = false;
219
+ $nodes[$key]->setMetadata(self::SORT_VISITED_KEY, $refGenerator[sizeof($refGenerator) - 1]);
220
+ }
221
+
222
+ // Iteratively peel off leaf nodes
223
+ $topologicalLevel = 0;
224
+ do {
225
+ // Find out which nodes are leafs (excluding visited nodes)
226
+ $leafNodes = array();
227
+ foreach($nodeKeys as $key) {
228
+ if ((!$nodes[$key]->getMetadata(self::SORT_VISITED_KEY)) && self::_nonVisitedInDegree($nodes[$key], self::SORT_VISITED_KEY) == 0) {
229
+ $leafNodes[] =& $nodes[$key];
230
+ }
231
+ }
232
+ // Mark leafs as visited
233
+ $refGenerator[] = $topologicalLevel;
234
+ for ($i=sizeof($leafNodes) - 1; $i>=0; $i--) {
235
+ $visited =& $leafNodes[$i]->getMetadata(self::SORT_VISITED_KEY);
236
+ $visited = true;
237
+ $leafNodes[$i]->setMetadata(self::SORT_VISITED_KEY, $visited);
238
+ $leafNodes[$i]->setMetadata(self::SORT_LEVEL_KEY, $refGenerator[sizeof($refGenerator) - 1]);
239
+ }
240
+ $topologicalLevel++;
241
+ } while (sizeof($leafNodes) > 0);
242
+
243
+ foreach($nodeKeys as $key) {
244
+ $nodes[$key]->unsetMetadata(self::SORT_VISITED_KEY);
245
+ }
246
+ }
247
+
248
+ }
downloader/lib/Mage/Connect/Structures/Node.php ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ class Mage_Connect_Structures_Node
28
+ {
29
+
30
+ protected $_data = null;
31
+ protected $_metadata = array();
32
+ protected $_arcs = array();
33
+ protected $_graph = null;
34
+
35
+ /**
36
+ * Node graph getter
37
+ *
38
+ * @return Mage_Connect_Structures_Graph
39
+ */
40
+ public function &getGraph()
41
+ {
42
+ return $this->_graph;
43
+ }
44
+
45
+ /**
46
+ *
47
+ * Node graph setter.
48
+ * This method should not be called directly.
49
+ * Use Graph::addNode instead.
50
+ *
51
+ * @param $graph
52
+ */
53
+ public function setGraph(&$graph)
54
+ {
55
+ $this->_graph =& $graph;
56
+ }
57
+
58
+ /**
59
+ *
60
+ * Node data getter.
61
+ *
62
+ * Each graph node can contain a reference to one variable. This is the getter for that reference.
63
+ *
64
+ * @return mixed Data stored in node
65
+ * @access public
66
+ */
67
+ public function &getData()
68
+ {
69
+ return $this->_data;
70
+ }
71
+
72
+ /**
73
+ * Node data setter
74
+ *
75
+ * Each graph node can contain a reference to one variable. This is the setter for that reference.
76
+ *
77
+ * @return mixed Data to store in node
78
+ */
79
+ public function setData($data)
80
+ {
81
+ $this->_data =& $data;
82
+ }
83
+
84
+ /**
85
+ *
86
+ * Test for existence of metadata under a given key.
87
+ *
88
+ * @param string Key to test
89
+ * @return boolean
90
+ * @access public
91
+ */
92
+ public function metadataKeyExists($key)
93
+ {
94
+ return array_key_exists($key, $this->_metadata);
95
+ }
96
+
97
+ /**
98
+ *
99
+ * Get node metadata
100
+ *
101
+ * @param string $key
102
+ * @param boolean $nullIfNonexistent (defaults to false).
103
+ * @return mixed
104
+ */
105
+ public function & getMetadata($key, $nullIfNonexistent = false)
106
+ {
107
+ if (array_key_exists($key, $this->_metadata)) {
108
+ return $this->_metadata[$key];
109
+ } elseif ($nullIfNonexistent) {
110
+ $a = null;
111
+ return $a;
112
+ } else {
113
+ throw new Exception(__METHOD__." : requested key doesn't exist: {$key}");
114
+ }
115
+ }
116
+
117
+ /**
118
+ *
119
+ * Delete metadata by key
120
+ *
121
+ * @param string Key
122
+ */
123
+ public function unsetMetadata($key)
124
+ {
125
+ if (array_key_exists($key, $this->_metadata)) {
126
+ unset($this->_metadata[$key]);
127
+ }
128
+
129
+ }
130
+
131
+ /**
132
+ *
133
+ * Node metadata setter
134
+ *
135
+ * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
136
+ * associative array or in a dictionary. This method stores data under the given key. If the key already exists,
137
+ * previously stored data is discarded.
138
+ *
139
+ * @param string $key
140
+ * @param mixed $data
141
+ */
142
+ public function setMetadata($key, $data)
143
+ {
144
+ $this->_metadata[$key] =& $data;
145
+ }
146
+
147
+ protected function _connectTo(&$destinationNode)
148
+ {
149
+ $this->_arcs[] =& $destinationNode;
150
+ }
151
+
152
+ /**
153
+ * Connect this node to another one.
154
+ * If the graph is not directed, the reverse arc, connecting $destinationNode to $this is also created.
155
+ * @param Structures_Graph Node to connect to
156
+ */
157
+ public function connectTo(&$destinationNode)
158
+ {
159
+ $class = get_class($this);
160
+ if(!$destinationNode instanceof $class) {
161
+ throw new Exception(__METHOD__." : argument should be instance of {$class}");
162
+ }
163
+
164
+ // Nodes must already be in graphs to be connected
165
+ if ($this->_graph == null) {
166
+ throw new Exception(__METHOD__." : tried to connect to null graph");
167
+ }
168
+
169
+ if ($destinationNode->getGraph() == null) {
170
+ throw new Exception(__METHOD__." : tried to connect to node that is not connected to any graph");
171
+ }
172
+
173
+ // Connect here
174
+ $this->_connectTo($destinationNode);
175
+ // If graph is undirected, connect back
176
+ if (!$this->_graph->isDirected()) {
177
+ $destinationNode->_connectTo($this);
178
+ }
179
+ }
180
+
181
+
182
+ /**
183
+ * Return nodes connected to this one.
184
+ * @return array
185
+ */
186
+ public function getNeighbours()
187
+ {
188
+ return $this->_arcs;
189
+ }
190
+
191
+ /**
192
+ * Test wether this node has an arc to the target node
193
+ * Returns true if the two nodes are connected
194
+ * @return boolean
195
+ */
196
+ public function connectsTo(&$target)
197
+ {
198
+ $arcKeys = array_keys($this->_arcs);
199
+ foreach($arcKeys as $key) {
200
+ $arc =& $this->_arcs[$key];
201
+ if ($target === $arc) {
202
+ return true;
203
+ }
204
+ }
205
+ return false;
206
+ }
207
+
208
+ /**
209
+ * Calculate the in degree of the node.
210
+ *
211
+ * The indegree for a node is the number of arcs
212
+ * entering the node.
213
+ *
214
+ * For non directed graphs:
215
+ * always outdegree = indegree.
216
+ *
217
+ * @return int
218
+ */
219
+ public function inDegree()
220
+ {
221
+ $result = 0;
222
+
223
+ if ($this->_graph == null) {
224
+ return $result;
225
+ }
226
+ if (!$this->_graph->isDirected()) {
227
+ return $this->outDegree();
228
+ }
229
+
230
+ $graphNodes =& $this->_graph->getNodes();
231
+ foreach (array_keys($graphNodes) as $key) {
232
+ if ($graphNodes[$key]->connectsTo($this)) {
233
+ $result++;
234
+ }
235
+ }
236
+ return $result;
237
+
238
+ }
239
+
240
+ /**
241
+ * Calculate the out degree of the node.
242
+ *
243
+ * The outdegree for a node is the number of arcs exiting the node.
244
+ * For non directed graphs:
245
+ * always outdegree = indegree.
246
+ *
247
+ * @return int
248
+ */
249
+ public function outDegree()
250
+ {
251
+ if ($this->_graph == null) {
252
+ return 0;
253
+ }
254
+ return count($this->_arcs);
255
+ }
256
+
257
+ }
downloader/lib/Mage/Connect/Validator.php ADDED
@@ -0,0 +1,440 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to validate string resources
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+
35
+ class Mage_Connect_Validator
36
+ {
37
+ protected static $_stability = array(0=>'devel',1=>'alpha',2=>'beta',3=>'stable');
38
+
39
+
40
+ public static function getStabilities()
41
+ {
42
+ return self::$_stability;
43
+ }
44
+
45
+
46
+
47
+ /**
48
+ * Compare stabilities. Returns:
49
+ *
50
+ * -1 if the first stability is lower than the second
51
+ * 0 if they are equal
52
+ * 1 if the second is lower.
53
+ * @param $s1
54
+ * @param $s2
55
+ * @return int
56
+ */
57
+ public function compareStabilities($s1, $s2)
58
+ {
59
+ $list = $this->getStabilities();
60
+ $tmp = array_combine(array_values($list),array_keys($list));
61
+
62
+ if(!isset($tmp[$s1], $tmp[$s2])) {
63
+ throw new Exception("Invalid stability in compareStabilities argument");
64
+ }
65
+
66
+
67
+ // 'stable' turns to 3
68
+ // 'devel' turns to 0
69
+ $s1 = $tmp[$s1];
70
+ $s2 = $tmp[$s2];
71
+ if($s1 === $s2) {
72
+ return 0;
73
+ } elseif($s1 > $s2) {
74
+ return 1;
75
+ } elseif($s1 < $s2) {
76
+ return -1;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Constructor
82
+ */
83
+ public function __construct()
84
+ {
85
+
86
+ }
87
+
88
+ /**
89
+ * Validate max len of string
90
+ * @param string $str
91
+ * @param int $maxLen
92
+ * @return bool
93
+ */
94
+ public function validateMaxLen($str, $maxLen)
95
+ {
96
+ return strlen((string) $str) <= (int) $maxLen;
97
+ }
98
+
99
+ /**
100
+ * Validate channel name and url
101
+ *
102
+ * @param mixed $str
103
+ * @return bool
104
+ */
105
+ public function validateChannelNameOrUri($str)
106
+ {
107
+ return ( $this->validateUrl($str) || $this->validatePackageName($str));
108
+ }
109
+
110
+ /**
111
+ * Validate License url
112
+ *
113
+ * @param mixed $str
114
+ * @return boolean
115
+ */
116
+ public function validateLicenseUrl($str)
117
+ {
118
+ if ($str) {
119
+ return ( $this->validateUrl($str) || $this->validatePackageName($str));
120
+ }
121
+ return true;
122
+ }
123
+
124
+ /**
125
+ * Validate compatible data
126
+ * @param array $data
127
+ * @return bool
128
+ */
129
+ public function validateCompatible(array $data)
130
+ {
131
+ if(!count($data)) {
132
+ /**
133
+ * Allow empty
134
+ */
135
+ return true;
136
+ }
137
+ $count = 0;
138
+ foreach($data as $k=>$v) {
139
+ foreach(array('name','channel','min','max') as $fld) {
140
+ $$fld = trim($v[$fld]);
141
+ }
142
+ $count++;
143
+
144
+ $res = $this->validateUrl($channel) && strlen($channel);
145
+ if(!$res) {
146
+ $this->addError("Invalid or empty channel in compat. #{$count}");
147
+ }
148
+
149
+ $res = $this->validatePackageName($name) && strlen($name);
150
+ if(!$res) {
151
+ $this->addError("Invalid or empty name in compat. #{$count}");
152
+ }
153
+ $res1 = $this->validateVersion($min);
154
+ if(!$res1) {
155
+ $this->addError("Invalid or empty minVersion in compat. #{$count}");
156
+ }
157
+ $res2 = $this->validateVersion($max);
158
+ if(!$res2) {
159
+ $this->addError("Invalid or empty maxVersion in compat. #{$count}");
160
+ }
161
+ if($res1 && $res2 && $this->versionLower($max, $min)) {
162
+ $this->addError("Max version is lower than min in compat #{$count}");
163
+ }
164
+
165
+ }
166
+ return ! $this->hasErrors();
167
+ }
168
+
169
+ /**
170
+ * Validate authors of package
171
+ * @param array $authors
172
+ * @return bool
173
+ */
174
+ public function validateAuthors(array $authors)
175
+ {
176
+ if(!count($authors)) {
177
+ $this->addError('Empty authors section');
178
+ return false;
179
+ }
180
+ $count = 0;
181
+ foreach($authors as $k=>$v) {
182
+ $count++;
183
+ array_map('trim', $v);
184
+ $name = $v['name'];
185
+ $login = $v['user'];
186
+ $email = $v['email'];
187
+ $res = $this->validateMaxLen($name, 256) && strlen($name);
188
+ if(!$res) {
189
+ $this->addError("Invalid or empty name for author #{$count}");
190
+ }
191
+ $res = $this->validatePackageName($login) && strlen($login);
192
+ if(!$res) {
193
+ $this->addError("Invalid or empty login for author #{$count}");
194
+ }
195
+ $res = $this->validateEmail($email);
196
+ if(!$res) {
197
+ $this->addError("Invalid or empty email for author #{$count}");
198
+ }
199
+ }
200
+ return ! $this->hasErrors();
201
+ }
202
+
203
+
204
+ /**
205
+ * Validator errors
206
+ * @var array
207
+ */
208
+ private $_errors = array();
209
+
210
+ /**
211
+ * Add error
212
+ * @param string $err
213
+ * @return
214
+ */
215
+ private function addError($err)
216
+ {
217
+ $this->_errors[] = $err;
218
+ }
219
+
220
+ /**
221
+ * Set validator errors
222
+ * @param array $err
223
+ * @return
224
+ */
225
+
226
+ private function setErrors(array $err)
227
+ {
228
+ $this->_errors = $err;
229
+ }
230
+
231
+ /**
232
+ * Clear validator errors
233
+ * @return
234
+ */
235
+ private function clearErrors()
236
+ {
237
+ $this->_errors = array();
238
+ }
239
+
240
+ /**
241
+ * Check if there are validator errors set
242
+ * @return unknown_type
243
+ */
244
+ public function hasErrors()
245
+ {
246
+ return count($this->_errors) != 0;
247
+ }
248
+
249
+
250
+ /**
251
+ * Get errors
252
+ * @param bool $clear if true after this call erros will be cleared
253
+ * @return array
254
+ */
255
+ public function getErrors($clear = true)
256
+ {
257
+ $out = $this->_errors;
258
+ if($clear) {
259
+ $this->clearErrors();
260
+ }
261
+ return $out;
262
+ }
263
+
264
+ /**
265
+ * Validate URL
266
+ * @param string $str
267
+ * @return bool
268
+ */
269
+ public function validateUrl($str)
270
+ {
271
+ $regex = "@([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}|"
272
+ ."(((news|telnet|nttp|file|http|ftp|https)://)|(www|ftp)"
273
+ ."[-A-Za-z0-9]*\\.)[-A-Za-z0-9\\.]+)(:[0-9]*)?@i";
274
+ return preg_match($regex, $str);
275
+ }
276
+
277
+
278
+ /**
279
+ * Validates package stability
280
+ * @param string $str
281
+ * @return bool
282
+ */
283
+ public function validateStability($str)
284
+ {
285
+ return in_array(strval($str), self::$_stability);
286
+ }
287
+
288
+ /**
289
+ * Validate date format
290
+ * @param $date
291
+ * @return bool
292
+ */
293
+ public function validateDate($date)
294
+ {
295
+ $subs = null;
296
+ $check1 = preg_match("/^([\d]{4})-([\d]{2})-([\d]{2})$/i", $date, $subs);
297
+ if(!$check1) {
298
+ return false;
299
+ }
300
+ return checkdate($subs[2], $subs[3], $subs[1]);
301
+ }
302
+
303
+
304
+ /**
305
+ * Validate email
306
+ * @param string $email
307
+ * @return bool
308
+ */
309
+ public function validateEmail($email)
310
+ {
311
+ return preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $email);
312
+ }
313
+
314
+ /**
315
+ * Validate package name
316
+ * @param $name
317
+ * @return bool
318
+ */
319
+ public function validatePackageName($name)
320
+ {
321
+ return preg_match("/^[a-zA-Z0-9_]+$/i", $name);
322
+ }
323
+
324
+ /**
325
+ * Validate version number
326
+ * @param string $version
327
+ * @return bool
328
+ */
329
+ public function validateVersion($version)
330
+ {
331
+ return preg_match("/^[\d]+\.[\d]+\.[\d]+([[:alnum:]\.\-\_]+)?$/i", $version);
332
+ }
333
+
334
+ /**
335
+ * Check versions are equal
336
+ * @param string $v1
337
+ * @param string $v2
338
+ * @return bool
339
+ */
340
+ public function versionEqual($v1, $v2)
341
+ {
342
+ return version_compare($v1, $v2, "==");
343
+ }
344
+
345
+ /**
346
+ * Check version $v1 <= $v2
347
+ * @param string $v1
348
+ * @param string $v2
349
+ * @return bool
350
+ */
351
+ public function versionLowerEqual($v1, $v2)
352
+ {
353
+ return version_compare($v1, $v2, "le");
354
+ }
355
+
356
+
357
+ /**
358
+ * Check if version $v1 lower than $v2
359
+ * @param string $v1
360
+ * @param string $v2
361
+ * @return bool
362
+ */
363
+ public function versionLower($v1, $v2)
364
+ {
365
+ return version_compare($v1, $v2, "<");
366
+ }
367
+
368
+ /**
369
+ * Check version $v1 >= $v2
370
+ * @param string $v1
371
+ * @param string $v2
372
+ * @return bool
373
+ */
374
+ public function versionGreaterEqual($v1, $v2)
375
+ {
376
+ return version_compare($v1, $v2, "ge");
377
+ }
378
+
379
+
380
+ /**
381
+ * Generic regex validation
382
+ * @param string $str
383
+ * @param string $regex
384
+ * @return bool
385
+ */
386
+ public function validateRegex($str, $regex)
387
+ {
388
+ return preg_match($regex, $str);
389
+ }
390
+
391
+
392
+ /**
393
+ * Check if PHP extension loaded
394
+ * @param string $name Extension name
395
+ * @return bool
396
+ */
397
+ public function validatePhpExtension($name)
398
+ {
399
+ return extension_loaded($name);
400
+ }
401
+
402
+
403
+ public function validatePHPVersion($min, $max, $ver = PHP_VERSION)
404
+ {
405
+ $minAccepted = true;
406
+ if($min) {
407
+ $minAccepted = version_compare($ver, $min, ">=");
408
+ }
409
+ $maxAccepted = true;
410
+ if($max) {
411
+ $maxAccepted = version_compare($ver, $max, "<=");
412
+ }
413
+ return (bool) $minAccepted && $maxAccepted;
414
+ }
415
+
416
+ /**
417
+ * Validate contents of package
418
+ *
419
+ * @param array $contents
420
+ * @param Mage_Connect_Config $config
421
+ * @return bool
422
+ */
423
+ public function validateContents(array $contents, $config)
424
+ {
425
+ if (!count($contents)) {
426
+ $this->addError('Empty package contents section');
427
+ return false;
428
+ }
429
+
430
+ $targetPath = rtrim($config->magento_root, "\\/");
431
+ foreach ($contents as $file) {
432
+ $dest = $targetPath . DS . $file;
433
+ if (file_exists($dest)) {
434
+ $this->addError("'{$file}' already exists");
435
+ return false;
436
+ }
437
+ }
438
+ return true;
439
+ }
440
+ }
downloader/lib/Mage/DB/Exception.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_DB
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * TODO
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Db
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_DB_Exception extends Exception {
35
+
36
+ }
downloader/lib/Mage/DB/Mysqli.php ADDED
@@ -0,0 +1,532 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_DB
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Mysqli database connector
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Db
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_DB_Mysqli
35
+ {
36
+ /**
37
+ * Default port
38
+ * @var int
39
+ */
40
+ const DEFAULT_PORT = 3306;
41
+
42
+ /**
43
+ * Table name escaper
44
+ * @var string
45
+ */
46
+ const TABLE_ESCAPER = '`';
47
+
48
+ /**
49
+ * Value escaper
50
+ * @var unknown_type
51
+ */
52
+ const VALUE_ESCAPER = '"';
53
+
54
+ /**
55
+ * Connection
56
+ * @var mysqli
57
+ */
58
+ protected $conn;
59
+ /**
60
+ * Fetch mode
61
+ * @var unknown_type
62
+ */
63
+ private $fetch_mode = MYSQLI_ASSOC;
64
+
65
+
66
+ /**
67
+ * Constructor
68
+ */
69
+ public function __construct()
70
+ {
71
+ $this->conn = new mysqli();
72
+ }
73
+
74
+ /**
75
+ * Connect
76
+ * @param string $host
77
+ * @param string $user
78
+ * @param string $paswd
79
+ * @param string $db
80
+ * @param int $port
81
+ * @return mixed
82
+ */
83
+ public function connect($host, $user, $paswd, $db, $port = self::DEFAULT_PORT)
84
+ {
85
+ $port = (int) $port;
86
+ $res = @$this->conn->connect($host, $user, $paswd, $db, $port);
87
+ if(0 !== mysqli_connect_errno($this->conn)) {
88
+ throw new Mage_DB_Exception(mysqli_connect_error($this->conn));
89
+ }
90
+ return $res;
91
+ }
92
+
93
+ /**
94
+ * Select database
95
+ * @param $db db name
96
+ * @return mixed
97
+ */
98
+ public function selectDb($db)
99
+ {
100
+ $res = mysqli_select_db($this->conn, $db);
101
+ return $res;
102
+ }
103
+
104
+ /**
105
+ * Escape string
106
+ * @param string $str
107
+ * @return string
108
+ */
109
+ public function escapeString($str)
110
+ {
111
+ return mysqli_real_escape_string($this->conn, $str);
112
+ }
113
+
114
+ /**
115
+ * Escape table name
116
+ * @param string $table
117
+ * @return string
118
+ */
119
+ public function escapeTableName($table)
120
+ {
121
+ return self::TABLE_ESCAPER.$this->escapeString($table).self::TABLE_ESCAPER;
122
+ }
123
+
124
+ /**
125
+ * Escape field name
126
+ * @param stirng $fld
127
+ * @return string
128
+ */
129
+ public function escapeFieldName($fld)
130
+ {
131
+ return self::TABLE_ESCAPER.$this->escapeString($fld).self::TABLE_ESCAPER;
132
+ }
133
+
134
+ /**
135
+ * Escape field value
136
+ * @param $data
137
+ * @return string
138
+ */
139
+ public function escapeFieldValue($data)
140
+ {
141
+ return self::VALUE_ESCAPER.$this->escapeString($data).self::VALUE_ESCAPER;
142
+ }
143
+
144
+ /**
145
+ * Fetch all rows
146
+ * @param $sql
147
+ * @return array
148
+ */
149
+ public function fetchAll($sql)
150
+ {
151
+ $res = $this->query($sql);
152
+ for($out = array(); $row = $res->fetch_array($this->fetch_mode); $out[] = $row);
153
+ return $out;
154
+ }
155
+
156
+ /**
157
+ * Fetch one row
158
+ * @param $sql
159
+ * @return array
160
+ */
161
+ public function fetchOne($sql)
162
+ {
163
+ $res = $this->query($sql);
164
+ return $res->fetch_array($this->fetch_mode);
165
+ }
166
+
167
+ /**
168
+ * Fetch rows grouped by key
169
+ * @param $sql
170
+ * @param $key
171
+ * @param $arrayMode force Array mode
172
+ * @return array
173
+ */
174
+ public function fetchGroupedArrayByKey($sql, $key, $arrayMode = true)
175
+ {
176
+ $res = $this->query($sql);
177
+ $out = array();
178
+ while($row = $res->fetch_array(MYSQLI_ASSOC)) {
179
+ if($arrayMode) {
180
+ if(!isset($out[$row[$key]])) {
181
+ $out[$row[$key]] = array();
182
+ }
183
+ $out[$row[$key]][] = $row;
184
+ } else {
185
+ $out[$row[$key]] = $row;
186
+ }
187
+ }
188
+ return $out;
189
+ }
190
+
191
+ /**
192
+ * Fetch one field from all rows and place to list
193
+ * @param string $sql
194
+ * @param string $fld
195
+ * @return array
196
+ */
197
+ public function fetchOneFieldAll($sql, $fld)
198
+ {
199
+ $res = $this->query($sql);
200
+ for($out = array(); $row = $res->fetch_array($this->fetch_mode); $out[] = $row[$fld]);
201
+ return $out;
202
+ }
203
+
204
+ /**
205
+ * List one item
206
+ * @param $table
207
+ * @param $condition
208
+ * @return array
209
+ */
210
+ public function listOne($table, $condition)
211
+ {
212
+ $table = $this->escapeTableName($table);
213
+ $sql = "SELECT * FROM {$table} WHERE {$condition}";
214
+ return $this->fetchOne($sql);
215
+ }
216
+
217
+ /**
218
+ * List items in table by condition
219
+ * @param string $table table name
220
+ * @param string $condition optional, if empty 1=1 is used
221
+ * @return array
222
+ */
223
+ public function listAll($table, $condition = '1=1')
224
+ {
225
+ $table = $this->escapeTableName($table);
226
+ $sql = "SELECT * FROM {$table} WHERE {$condition}";
227
+ return $this->fetchAll($sql);
228
+ }
229
+
230
+ /**
231
+ * List by key single entry
232
+ * @param string $table table name
233
+ * @param string $value field value
234
+ * @param string $key field name
235
+ * @return array
236
+ */
237
+ public function listByKeyOne($table, $value, $key = 'id')
238
+ {
239
+ $table = $this->escapeTableName($table);
240
+ $key = $this->escapeFieldName($key);
241
+ $value = $this->escapeFieldValue($value);
242
+ $sql = "SELECT * FROM {$table} WHERE {$key} = {$value}";
243
+ return $this->fetchOne($sql);
244
+ }
245
+
246
+ /**
247
+ * List by key all rows in table
248
+ * @param string $table table name
249
+ * @param string $value value of key field
250
+ * @param string $key key field name
251
+ * @param string $add additional conditions
252
+ * @return array
253
+ */
254
+ public function listByKeyAll($table, $value, $key = 'id', $add = '')
255
+ {
256
+ $table = $this->escapeTableName($table);
257
+ $key = $this->escapeFieldName($key);
258
+ $value = $this->escapeFieldValue($value);
259
+ $sql = "SELECT * FROM {$table} WHERE {$key} = {$value} {$add}";
260
+ return $this->fetchAll($sql);
261
+ }
262
+
263
+ /**
264
+ * List by key grouped
265
+ * @param string $table
266
+ * @param string $key
267
+ * @param bool $forcedArrayMode
268
+ * @return array
269
+ */
270
+ public function listByKeyGrouped($table, $key = 'id', $forcedArrayMode = false)
271
+ {
272
+ $table = $this->escapeTableName($table);
273
+ $sql = "SELECT * FROM {$table}";
274
+ return $this->fetchGroupedArrayByKey($sql, $key, $forcedArrayMode);
275
+ }
276
+
277
+
278
+ /**
279
+ * Escape field names
280
+ * @param array $arrNames
281
+ * @return array
282
+ */
283
+ public function escapeFieldNames(array $arrNames)
284
+ {
285
+ $out = array();
286
+ for ($i=0, $c = count($arrNames) ; $i<$c; $i++) {
287
+ $out[] = $this->escapeFieldName($arrNames[$i]);
288
+ }
289
+ return $out;
290
+ }
291
+
292
+ /**
293
+ * Escape field values
294
+ * @param array $arrNames
295
+ * @return array
296
+ */
297
+ public function escapeFieldValues(array $arrNames)
298
+ {
299
+ $out = array();
300
+ for ($i=0, $c = count($arrNames) ; $i<$c; $i++) {
301
+ if($arrNames[$i] !== 'LAST_INSERT_ID()') {
302
+ $out[] = $this->escapeFieldValue($arrNames[$i]);
303
+ } else {
304
+ $out[] = $arrNames[$i];
305
+ }
306
+ }
307
+ return $out;
308
+ }
309
+
310
+
311
+ /**
312
+ * Throw connect exception
313
+ * @throws Mage_DB_Exception
314
+ * @return void
315
+ */
316
+ protected function throwConnectException()
317
+ {
318
+ throw new Mage_DB_Exception($this->conn->connect_error);
319
+ }
320
+
321
+ /**
322
+ * Query - perform with throwing exception on error
323
+ * @param sting $sql query
324
+ * @throws Mage_DB_Exception
325
+ * @return mixed
326
+ */
327
+ public function query($sql)
328
+ {
329
+ $res = $this->unsafeQuery($sql);
330
+ if(!$res) {
331
+ throw new Mage_DB_Exception($this->conn->error);
332
+ }
333
+ return $res;
334
+ }
335
+
336
+ /**
337
+ * Unsafe query - perform without error checking
338
+ * @param string $sql query
339
+ * @return mixed
340
+ */
341
+ public function unsafeQuery($sql)
342
+ {
343
+ return $this->conn->query($sql);
344
+ }
345
+
346
+ /**
347
+ * Insert assoc array to table
348
+ * @param string $table
349
+ * @param array $data
350
+ * @param bool $replace
351
+ * @return mixed
352
+ */
353
+ public function insertAssocOne($table, array $data, $replace = false) {
354
+ $keys = $this->escapeFieldNames(array_keys($data));
355
+ $keys = "(" . implode (",", $keys) . ")";
356
+ $table = $this->escapeTableName($table);
357
+ $sql = $replace ? "REPLACE INTO {$table} " : "INSERT INTO {$table} ";
358
+ $values = $this->escapeFieldValues(array_values($data));
359
+ $values = " VALUES (" . implode (",", $values) . ")";
360
+ $sql .= $keys . $values;
361
+ return $this->query($sql);
362
+ }
363
+
364
+ /**
365
+ * Insert several records to table
366
+ * @param string $table
367
+ * @param array $data
368
+ * @param bool $replace use REPLACE INTO instead of INSERT INTO
369
+ * @return array
370
+ */
371
+ public function insertAssocMultiple($table, array $data, $replace = false, $excludeFields = array())
372
+ {
373
+ $table = $this->escapeTableName($table);
374
+ $sql = $replace ? "REPLACE INTO {$table} " : "INSERT INTO {$table} ";
375
+ $keys = array_keys($data[0]);
376
+ $excluded = array();
377
+ for($i = 0, $c = count($excludeFields); $i < $c; $i++) {
378
+ $k = $excludeFields[$i];
379
+ if(isset($keys[$k])) {
380
+ $excluded [] = $k;
381
+ unset($keys[$k]);
382
+ }
383
+ }
384
+
385
+ $keys = $this->escapeFieldNames($keys);
386
+ $sql .= " ( ";
387
+ for($i = 0, $c = count($keys); $i<$c; $i++) {
388
+ $sql .= $keys[$i];
389
+ if($i!=$c-1) {
390
+ $sql .= ",";
391
+ }
392
+ }
393
+ $sql .= " ) VALUES ";
394
+ for($i = 0, $c = count($data); $i<$c; $i++) {
395
+ $row = $data[$i];
396
+ for ($j = 0, $jc = count($excluded); $j<$jc; $j++) {
397
+ unset($data[$excluded[$j]]);
398
+ }
399
+ $values = $this->escapeFieldValues(array_values($row));
400
+ $sql .= "( ";
401
+ for ($j = 0, $jc = count($values); $j < $jc; $j++) {
402
+ $sql .= $values[$j];
403
+ if($j != $jc-1) {
404
+ $sql .= ",";
405
+ }
406
+ }
407
+ $sql .= " )";
408
+ if($i!=$c-1) {
409
+ $sql .= ",";
410
+ }
411
+ }
412
+ return $this->query($sql);
413
+ }
414
+
415
+
416
+ /**
417
+ * Set table data by condition
418
+ * @param $table
419
+ * @param $data
420
+ * @param $condition
421
+ * @return mixed
422
+ */
423
+ public function updateAssoc($table, array $data, $condition = '1=1')
424
+ {
425
+ $table = $this->escapeTableName($table);
426
+ $set = array();
427
+ foreach($data as $k=>$v) {
428
+ $k = $this->escapeFieldName($k);
429
+ $v = $this->escapeFieldValue($v);
430
+ $set[] = $k . " = " . $v;
431
+ }
432
+ $set = implode(",", $set);
433
+ $sql = "UPDATE {$table} SET {$set} WHERE {$condition}";
434
+ return $this->query($sql);
435
+ }
436
+
437
+
438
+ /**
439
+ * Update entry by pk
440
+ * @param string $table
441
+ * @param array $data
442
+ * @param string $value
443
+ * @param string $key
444
+ * @return mixed
445
+ */
446
+ public function updateAssocByKey($table, array $data, $value, $key = 'id')
447
+ {
448
+ $table = $this->escapeTableName($table);
449
+ $key = $this->escapeFieldName($key);
450
+ $value = $this->escapeFieldValue($value);
451
+ $set = array();
452
+ foreach($data as $k=>$v) {
453
+ $k = $this->escapeFieldName($k);
454
+ $v = $this->escapeFieldValue($v);
455
+ $set[] = $k . " = " . $v;
456
+ }
457
+ $set = implode(",", $set);
458
+ $sql = "UPDATE {$table} SET {$set} WHERE {$key} = {$value}";
459
+ return $this->query($sql);
460
+ }
461
+
462
+
463
+ /**
464
+ * Convert ids to string
465
+ * @param array|string $ids
466
+ * @return string
467
+ */
468
+ public function idsToString($ids)
469
+ {
470
+ if(is_scalar($ids)) {
471
+ return $this->escapeFieldValue(strval($ids));
472
+ }
473
+ $out = array();
474
+ foreach ($values as $id) {
475
+ $out .= $this->escapeFieldValue($id);
476
+ }
477
+ return implode(",", $out);
478
+ }
479
+
480
+ /**
481
+ * Ids equality condition
482
+ * @param mixed $ids array or string
483
+ * @return string
484
+ */
485
+ public function idsEqualCondition($ids)
486
+ {
487
+ $vals = $this->idsToString($ids);
488
+ $condition = is_scalar($ids) ? " = {$vals} " : " IN ({$vals}) ";
489
+ return $condition;
490
+ }
491
+
492
+
493
+ /**
494
+ * Delete items by id
495
+ * @param string $table
496
+ * @param mixed $ids array or string
497
+ * @param string $key key field
498
+ * @return mixed
499
+ */
500
+ public function deleteById($table, $ids, $key = 'id')
501
+ {
502
+ $key = $this->escapeFieldName($key);
503
+ $cond = $this->idsEqualCondition($ids);
504
+ $table = $this->escapeTableName($table);
505
+ $sql = "DELETE FROM {$table} WHERE {$key} {$cond}";
506
+ return $this->query($sql);
507
+ }
508
+
509
+ /**
510
+ * Count items in table by condition
511
+ * @param string $table
512
+ * @param string $condition ex: "a>0"
513
+ * @return int
514
+ */
515
+ public function simpleCount($table, $condition) {
516
+ $sql = "SELECT count(*) AS `cnt` WHERE {$condition}";
517
+ $data = $this->fetchOne($sql);
518
+ if(empty($data['cnt'])) {
519
+ return 0;
520
+ }
521
+ return intval($data['cnt']);
522
+
523
+ }
524
+
525
+ public function lastInsertId()
526
+ {
527
+ $sql = "SELECT LAST_INSERT_ID() as `id`";
528
+ $data = $this->fetchOne($sql);
529
+ return $data['id'];
530
+ }
531
+
532
+ }
downloader/lib/Mage/Exception.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Exception
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class for Exception
29
+ *
30
+ * @category Mage
31
+ * @package Mage
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_Exception extends Exception
35
+ {}
downloader/lib/Mage/HTTP/Client.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_HTTP
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Factory for HTTP client classes
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+
35
+ class Mage_HTTP_Client
36
+ {
37
+
38
+ /**
39
+ * Disallow to instantiate - pvt constructor
40
+ */
41
+ private function __construct()
42
+ {
43
+
44
+ }
45
+
46
+
47
+ /**
48
+ * Factory for HTTP client
49
+ * @param string/false $frontend 'curl'/'socket' or false for auto-detect
50
+ * @return Mage_HTTP_IClient
51
+ */
52
+ public static function getInstance($frontend = false)
53
+ {
54
+ if(false === $frontend)
55
+ {
56
+ $frontend = self::detectFrontend();
57
+ }
58
+ if(false === $frontend)
59
+ {
60
+ throw new Exception("Cannot find frontend automatically, set it manually");
61
+ }
62
+
63
+ $class = __CLASS__."_".str_replace(' ', DIRECTORY_SEPARATOR, ucwords(str_replace('_', ' ', $frontend)));
64
+ $obj = new $class();
65
+ return $obj;
66
+ }
67
+
68
+ /**
69
+ * Detects frontend type.
70
+ * Priority is given to CURL
71
+ *
72
+ * @return string/bool
73
+ */
74
+ protected static function detectFrontend()
75
+ {
76
+ if(function_exists("curl_init")) {
77
+ return "curl";
78
+ }
79
+ if(function_exists("fsockopen")) {
80
+ return "socket";
81
+ }
82
+ return false;
83
+ }
84
+ }
downloader/lib/Mage/HTTP/Client/Curl.php ADDED
@@ -0,0 +1,556 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_HTTP
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to work with HTTP protocol using curl library
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_HTTP_Client_Curl
35
+ implements Mage_HTTP_IClient
36
+ {
37
+ /**
38
+ * Session Cookie storage, magento_root/var directory used
39
+ * @var string
40
+ */
41
+ const COOKIE_FILE = 'var/cookie';
42
+
43
+ /**
44
+ * Hostname
45
+ * @var string
46
+ */
47
+ protected $_host = 'localhost';
48
+
49
+ /**
50
+ * Port
51
+ * @var int
52
+ */
53
+ protected $_port = 80;
54
+
55
+ /**
56
+ * Stream resource
57
+ * @var object
58
+ */
59
+ protected $_sock = null;
60
+
61
+ /**
62
+ * Request headers
63
+ * @var array
64
+ */
65
+ protected $_headers = array();
66
+
67
+
68
+ /**
69
+ * Fields for POST method - hash
70
+ * @var array
71
+ */
72
+ protected $_postFields = array();
73
+
74
+ /**
75
+ * Request cookies
76
+ * @var array
77
+ */
78
+ protected $_cookies = array();
79
+
80
+ /**
81
+ * Response headers
82
+ * @var array
83
+ */
84
+ protected $_responseHeaders = array();
85
+
86
+ /**
87
+ * Response body
88
+ * @var string
89
+ */
90
+ protected $_responseBody = '';
91
+
92
+ /**
93
+ * Response status
94
+ * @var int
95
+ */
96
+ protected $_responseStatus = 0;
97
+
98
+
99
+ /**
100
+ * Request timeout
101
+ * @var intunknown_type
102
+ */
103
+ protected $_timeout = 300;
104
+
105
+ /**
106
+ * TODO
107
+ * @var int
108
+ */
109
+ protected $_redirectCount = 0;
110
+
111
+ /**
112
+ * Curl
113
+ * @var object
114
+ */
115
+ protected $_ch;
116
+
117
+
118
+ /**
119
+ * User ovverides options hash
120
+ * Are applied before curl_exec
121
+ *
122
+ * @var array();
123
+ */
124
+ protected $_curlUserOptions = array();
125
+
126
+ /**
127
+ * User credentials
128
+ *
129
+ * @var array();
130
+ */
131
+ protected $_auth = array();
132
+
133
+ /**
134
+ * Set request timeout, msec
135
+ *
136
+ * @param int $value
137
+ */
138
+ public function setTimeout($value)
139
+ {
140
+ $this->_timeout = (int) $value;
141
+ }
142
+
143
+ /**
144
+ * Constructor
145
+ */
146
+ public function __construct()
147
+ {
148
+
149
+ }
150
+
151
+ /**
152
+ * Destructor
153
+ * Removes temporary environment
154
+ */
155
+ public function __destruct()
156
+ {
157
+ if (is_file(self::COOKIE_FILE)) {
158
+ @unlink(self::COOKIE_FILE);
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Set headers from hash
164
+
165
+ * @param array $headers
166
+ */
167
+ public function setHeaders($headers)
168
+ {
169
+ $this->_headers = $headers;
170
+
171
+ }
172
+
173
+ /**
174
+ * Add header
175
+ *
176
+ * @param $name name, ex. "Location"
177
+ * @param $value value ex. "http://google.com"
178
+ */
179
+ public function addHeader($name, $value)
180
+ {
181
+ $this->_headers[$name] = $value;
182
+ }
183
+
184
+ /**
185
+ * Remove specified header
186
+ *
187
+ * @param string $name
188
+ */
189
+ public function removeHeader($name)
190
+ {
191
+ unset($this->_headers[$name]);
192
+
193
+ }
194
+
195
+ /**
196
+ * Authorization: Basic header
197
+ * Login credentials support
198
+ *
199
+ * @param string $login username
200
+ * @param string $pass password
201
+ */
202
+ public function setCredentials($login, $pass)
203
+ {
204
+ $this->_auth['login'] = $login;
205
+ $this->_auth['password'] = $pass;
206
+ //$val= base64_encode( "$login:$pass" );
207
+ //$this->addHeader( "Authorization", "Basic $val" );
208
+ }
209
+
210
+ /**
211
+ * Add cookie
212
+ *
213
+ * @param string $name
214
+ * @param string $value
215
+ */
216
+ public function addCookie($name, $value)
217
+ {
218
+ $this->_cookies[$name] = $value;
219
+ }
220
+
221
+ /**
222
+ * Remove cookie
223
+ *
224
+ * @param string $name
225
+ */
226
+ public function removeCookie($name)
227
+ {
228
+ unset($this->_cookies[$name]);
229
+ }
230
+
231
+ /**
232
+ * Set cookies array
233
+ *
234
+ * @param array $cookies
235
+ */
236
+ public function setCookies($cookies)
237
+ {
238
+ $this->_cookies = $cookies;
239
+ }
240
+
241
+ /**
242
+ * Clear cookies
243
+ */
244
+ public function removeCookies()
245
+ {
246
+ $this->setCookies(array());
247
+ }
248
+
249
+
250
+ /**
251
+ * Make GET request
252
+ *
253
+ * @param string $uri uri relative to host, ex. "/index.php"
254
+ */
255
+ public function get($uri)
256
+ {
257
+ $this->makeRequest("GET", $uri);
258
+ }
259
+
260
+ /**
261
+ * Make POST request
262
+ * @see lib/Mage/HTTP/Mage_HTTP_Client#post($uri, $params)
263
+ */
264
+ public function post($uri, $params)
265
+ {
266
+ $this->makeRequest("POST", $uri, $params);
267
+ }
268
+
269
+
270
+ /**
271
+ * Get response headers
272
+ *
273
+ * @return array
274
+ */
275
+ public function getHeaders()
276
+ {
277
+ return $this->_responseHeaders;
278
+ }
279
+
280
+
281
+ /**
282
+ * Get response body
283
+ *
284
+ * @return string
285
+ */
286
+ public function getBody()
287
+ {
288
+ return $this->_responseBody;
289
+ }
290
+
291
+ /**
292
+ * Get cookies response hash
293
+ *
294
+ * @return array
295
+ */
296
+ public function getCookies()
297
+ {
298
+ if(empty($this->_responseHeaders['Set-Cookie'])) {
299
+ return array();
300
+ }
301
+ $out = array();
302
+ foreach( $this->_responseHeaders['Set-Cookie'] as $row) {
303
+ $values = explode("; ", $row);
304
+ $c = count($values);
305
+ if(!$c) {
306
+ continue;
307
+ }
308
+ list($key, $val) = explode("=", $values[0]);
309
+ if(is_null($val)) {
310
+ continue;
311
+ }
312
+ $out[trim($key)] = trim($val);
313
+ }
314
+ return $out;
315
+ }
316
+
317
+
318
+ /**
319
+ * Get cookies array with details
320
+ * (domain, expire time etc)
321
+ * @return array
322
+ */
323
+ public function getCookiesFull()
324
+ {
325
+ if(empty($this->_responseHeaders['Set-Cookie'])) {
326
+ return array();
327
+ }
328
+ $out = array();
329
+ foreach( $this->_responseHeaders['Set-Cookie'] as $row) {
330
+ $values = explode("; ", $row);
331
+ $c = count($values);
332
+ if(!$c) {
333
+ continue;
334
+ }
335
+ list($key, $val) = explode("=", $values[0]);
336
+ if(is_null($val)) {
337
+ continue;
338
+ }
339
+ $out[trim($key)] = array('value'=>trim($val));
340
+ array_shift($values);
341
+ $c--;
342
+ if(!$c) {
343
+ continue;
344
+ }
345
+ for($i = 0; $i<$c; $i++) {
346
+ list($subkey, $val) = explode("=", $values[$i]);
347
+ $out[trim($key)][trim($subkey)] = trim($val);
348
+ }
349
+ }
350
+ return $out;
351
+ }
352
+
353
+ /**
354
+ * Get response status code
355
+ * @see lib/Mage/HTTP/Mage_HTTP_Client#getStatus()
356
+ */
357
+ public function getStatus()
358
+ {
359
+ return $this->_responseStatus;
360
+ }
361
+
362
+ /**
363
+ * Make request
364
+ * @param string $method
365
+ * @param string $uri
366
+ * @param array $params
367
+ * @return null
368
+ */
369
+ protected function makeRequest($method, $uri, $params = array())
370
+ {
371
+ static $isAuthorizationRequired = 0;
372
+ $this->_ch = curl_init();
373
+
374
+ // make request via secured layer
375
+ if ($isAuthorizationRequired && strpos($uri, 'https://') !== 0) {
376
+ $uri = str_replace('http://', '', $uri);
377
+ $uri = 'https://' . $uri;
378
+ }
379
+
380
+ $this->curlOption(CURLOPT_URL, $uri);
381
+ $this->curlOption(CURLOPT_SSL_VERIFYPEER, FALSE);
382
+ $this->curlOption(CURLOPT_SSL_VERIFYHOST, 2);
383
+
384
+ // force method to POST if secured
385
+ if ($isAuthorizationRequired) {
386
+ $method = 'POST';
387
+ }
388
+
389
+ if($method == 'POST') {
390
+ $this->curlOption(CURLOPT_POST, 1);
391
+ $postFields = is_array($params) ? $params : array();
392
+ if ($isAuthorizationRequired) {
393
+ $this->curlOption(CURLOPT_COOKIEJAR, self::COOKIE_FILE);
394
+ $this->curlOption(CURLOPT_COOKIEFILE, self::COOKIE_FILE);
395
+ $postFields = array_merge($postFields, $this->_auth);
396
+ }
397
+ if (!empty($postFields)) {
398
+ $this->curlOption(CURLOPT_POSTFIELDS, $postFields);
399
+ }
400
+ } elseif($method == "GET") {
401
+ $this->curlOption(CURLOPT_HTTPGET, 1);
402
+ } else {
403
+ $this->curlOption(CURLOPT_CUSTOMREQUEST, $method);
404
+ }
405
+
406
+ if(count($this->_headers)) {
407
+ $heads = array();
408
+ foreach($this->_headers as $k=>$v) {
409
+ $heads[] = $k.': '.$v;
410
+ }
411
+ $this->curlOption(CURLOPT_HTTPHEADER, $heads);
412
+ }
413
+
414
+ if(count($this->_cookies)) {
415
+ $cookies = array();
416
+ foreach($this->_cookies as $k=>$v) {
417
+ $cookies[] = "$k=$v";
418
+ }
419
+ $this->curlOption(CURLOPT_COOKIE, implode(";", $cookies));
420
+ }
421
+
422
+ if($this->_timeout) {
423
+ $this->curlOption(CURLOPT_TIMEOUT, $this->_timeout);
424
+ }
425
+
426
+ if($this->_port != 80) {
427
+ $this->curlOption(CURLOPT_PORT, $this->_port);
428
+ }
429
+
430
+ $this->curlOption(CURLOPT_RETURNTRANSFER, 1);
431
+ $this->curlOption(CURLOPT_FOLLOWLOCATION, 1);
432
+ $this->curlOption(CURLOPT_HEADERFUNCTION, array($this,'parseHeaders'));
433
+
434
+ if(count($this->_curlUserOptions)) {
435
+ foreach($this->_curlUserOptions as $k=>$v) {
436
+ $this->curlOption($k, $v);
437
+ }
438
+ }
439
+
440
+ $this->_responseHeaders = array();
441
+ $this->_responseBody = curl_exec($this->_ch);
442
+ $err = curl_errno($this->_ch);
443
+ if($err) {
444
+ $this->doError(curl_error($this->_ch));
445
+ }
446
+ if(!$this->getStatus()) {
447
+ return $this->doError("Invalid response headers returned from server.");
448
+ }
449
+ curl_close($this->_ch);
450
+ if (403 == $this->getStatus()) {
451
+ if (!$isAuthorizationRequired) {
452
+ $isAuthorizationRequired++;
453
+ $this->makeRequest($method, $uri, $params);
454
+ $isAuthorizationRequired=0;
455
+ } else {
456
+ return $this->doError(sprintf('Access denied for %s@%s', $_SESSION['auth']['login'], $uri));
457
+ }
458
+ }
459
+ }
460
+
461
+ /**
462
+ * Throw error excpetion
463
+ * @param $string
464
+ * @throws Exception
465
+ */
466
+ public function isAuthorizationRequired()
467
+ {
468
+ if (isset($_SESSION['auth']['username']) && isset($_SESSION['auth']['password']) && !empty($_SESSION['auth']['username'])) {
469
+ return true;
470
+ }
471
+ return false;
472
+ }
473
+
474
+ /**
475
+ * Throw error excpetion
476
+ * @param $string
477
+ * @throws Exception
478
+ */
479
+ public function doError($string)
480
+ {
481
+ throw new Exception($string);
482
+ }
483
+
484
+
485
+ /**
486
+ * Parse headers - CURL callback functin
487
+ *
488
+ * @param resource $ch curl handle, not needed
489
+ * @param string $data
490
+ * @return int
491
+ */
492
+ protected function parseHeaders($ch, $data)
493
+ {
494
+ if(preg_match('/^HTTP\/[\d\.x]+ (\d+)/', $data, $m)) {
495
+ if (isset($m[1])) {
496
+ $this->_responseStatus = (int)$m[1];
497
+ }
498
+ } else {
499
+ $name = $value = '';
500
+ $out = explode(": ", trim($data), 2);
501
+ if(count($out) == 2) {
502
+ $name = $out[0];
503
+ $value = $out[1];
504
+ }
505
+
506
+ if(strlen($name)) {
507
+ if("Set-Cookie" == $name) {
508
+ if(!isset($this->_responseHeaders[$name])) {
509
+ $this->_responseHeaders[$name] = array();
510
+ }
511
+ $this->_responseHeaders[$name][] = $value;
512
+ } else {
513
+ $this->_responseHeaders[$name] = $value;
514
+ }
515
+ }
516
+ }
517
+
518
+ return strlen($data);
519
+ }
520
+
521
+ /**
522
+ * Set curl option directly
523
+ *
524
+ * @param string $name
525
+ * @param string $value
526
+ */
527
+ protected function curlOption($name, $value)
528
+ {
529
+ curl_setopt($this->_ch, $name, $value);
530
+ }
531
+
532
+ /**
533
+ * Set curl options array directly
534
+ * @param array $array
535
+ */
536
+ protected function curlOptions($array)
537
+ {
538
+ curl_setopt_array($this->_ch, $arr);
539
+ }
540
+
541
+ /**
542
+ * Set CURL options ovverides array *
543
+ */
544
+ public function setOptions($arr)
545
+ {
546
+ $this->_curlUserOptions = $arr;
547
+ }
548
+
549
+ /**
550
+ * Set curl option
551
+ */
552
+ public function setOption($name, $value)
553
+ {
554
+ $this->_curlUserOptions[$name] = $value;
555
+ }
556
+ }
downloader/lib/Mage/HTTP/Client/Socket.php ADDED
@@ -0,0 +1,537 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_HTTP
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Class to work with HTTP protocol using sockets
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mage_HTTP_Client_Socket
35
+ implements Mage_HTTP_IClient
36
+ {
37
+ /**
38
+ * Hostname
39
+ * @var string
40
+ */
41
+ private $_host = 'localhost';
42
+
43
+ /**
44
+ * Port
45
+ * @var int
46
+ */
47
+ private $_port = 80;
48
+
49
+ /**
50
+ * Stream resource
51
+ * @var object
52
+ */
53
+ private $_sock = null;
54
+
55
+ /**
56
+ * Request headers
57
+ * @var array
58
+ */
59
+ private $_headers = array();
60
+
61
+
62
+ /**
63
+ * Fields for POST method - hash
64
+ * @var array
65
+ */
66
+ private $_postFields = array();
67
+
68
+ /**
69
+ * Request cookies
70
+ * @var array
71
+ */
72
+ private $_cookies = array();
73
+
74
+ /**
75
+ * Response headers
76
+ * @var array
77
+ */
78
+ private $_responseHeaders = array();
79
+
80
+ /**
81
+ * Response body
82
+ * @var string
83
+ */
84
+ private $_responseBody = '';
85
+
86
+ /**
87
+ * Response status
88
+ * @var int
89
+ */
90
+ private $_responseStatus = 0;
91
+
92
+
93
+ /**
94
+ * Request timeout
95
+ * @var int
96
+ */
97
+ private $_timeout = 300;
98
+
99
+ /**
100
+ * TODO
101
+ * @var int
102
+ */
103
+ private $_redirectCount = 0;
104
+
105
+
106
+ /**
107
+ * Set request timeout, msec
108
+ *
109
+ * @param int $value
110
+ */
111
+ public function setTimeout($value)
112
+ {
113
+ $this->_timeout = (int) $value;
114
+ }
115
+
116
+ /**
117
+ * Constructor
118
+ * @param string $host
119
+ * @param int $port
120
+ */
121
+ public function __construct($host = null, $port = 80)
122
+ {
123
+ if($host) {
124
+ $this->connect($host, (int) $port);
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Set connection params
130
+ *
131
+ * @param string $host
132
+ * @param int $port
133
+ */
134
+ public function connect($host, $port = 80)
135
+ {
136
+ $this->_host = $host;
137
+ $this->_port = (int) $port;
138
+
139
+ }
140
+
141
+ /**
142
+ * Disconnect
143
+ */
144
+ public function disconnect()
145
+ {
146
+ @fclose($this->_sock);
147
+ }
148
+
149
+ /**
150
+ * Set headers from hash
151
+
152
+ * @param array $headers
153
+ */
154
+ public function setHeaders($headers)
155
+ {
156
+ $this->_headers = $headers;
157
+
158
+ }
159
+
160
+ /**
161
+ * Add header
162
+ *
163
+ * @param $name name, ex. "Location"
164
+ * @param $value value ex. "http://google.com"
165
+ */
166
+ public function addHeader($name, $value)
167
+ {
168
+ $this->_headers[$name] = $value;
169
+
170
+ }
171
+
172
+ /**
173
+ * Remove specified header
174
+ *
175
+ * @param string $name
176
+ */
177
+ public function removeHeader($name)
178
+ {
179
+ unset($this->_headers[$name]);
180
+
181
+ }
182
+
183
+ /**
184
+ * Authorization: Basic header
185
+ * Login credentials support
186
+ *
187
+ * @param string $login username
188
+ * @param string $pass password
189
+ */
190
+ public function setCredentials($login, $pass)
191
+ {
192
+ $val= base64_encode( "$login:$pass" );
193
+ $this->addHeader( "Authorization", "Basic $val" );
194
+ }
195
+
196
+ /**
197
+ * Add cookie
198
+ *
199
+ * @param string $name
200
+ * @param string $value
201
+ */
202
+ public function addCookie($name, $value)
203
+ {
204
+ $this->_cookies[$name] = $value;
205
+ }
206
+
207
+ /**
208
+ * Remove cookie
209
+ *
210
+ * @param string $name
211
+ */
212
+ public function removeCookie($name)
213
+ {
214
+ unset($this->_cookies[$name]);
215
+ }
216
+
217
+ /**
218
+ * Set cookies array
219
+ *
220
+ * @param array $cookies
221
+ */
222
+ public function setCookies($cookies)
223
+ {
224
+ $this->_cookies = $cookies;
225
+ }
226
+
227
+ /**
228
+ * Clear cookies
229
+ */
230
+ public function removeCookies()
231
+ {
232
+ $this->setCookies(array());
233
+ }
234
+
235
+
236
+ /**
237
+ * Make GET request
238
+ *
239
+ * @param string $uri full uri path
240
+ */
241
+ public function get($uri)
242
+ {
243
+ $this->makeRequest("GET",$this->parseUrl($uri));
244
+ }
245
+
246
+ /**
247
+ * Set host, port from full url
248
+ * and return relative url
249
+ *
250
+ * @param string $uri ex. http://google.com/index.php?a=b
251
+ * @return string ex. /index.php?a=b
252
+ */
253
+ protected function parseUrl($uri)
254
+ {
255
+ $parts = parse_url($uri);
256
+ if(!empty($parts['user']) && !empty($parts['pass'])) {
257
+ $this->setCredentials($parts['user'], $parts['pass']);
258
+ }
259
+ if(!empty($parts['port'])) {
260
+ $this->_port = (int) $parts['port'];
261
+ }
262
+
263
+ if(!empty($parts['host'])) {
264
+ $this->_host = $parts['host'];
265
+ } else {
266
+ throw new InvalidArgumentException("Uri doesn't contain host part");
267
+ }
268
+
269
+
270
+ if(!empty($parts['path'])) {
271
+ $requestUri = $parts['path'];
272
+ } else {
273
+ throw new InvalidArgumentException("Uri doesn't contain path part");
274
+ }
275
+ if(!empty($parts['query'])) {
276
+ $requestUri .= "?".$parts['query'];
277
+ }
278
+ return $requestUri;
279
+ }
280
+
281
+ /**
282
+ * Make POST request
283
+ */
284
+ public function post($uri, $params)
285
+ {
286
+ $this->makeRequest("POST", $this->parseUrl($uri), $params);
287
+ }
288
+
289
+
290
+ /**
291
+ * Get response headers
292
+ *
293
+ * @return array
294
+ */
295
+ public function getHeaders()
296
+ {
297
+ return $this->_responseHeaders;
298
+ }
299
+
300
+
301
+ /**
302
+ * Get response body
303
+ *
304
+ * @return string
305
+ */
306
+ public function getBody()
307
+ {
308
+ return $this->_responseBody;
309
+ }
310
+
311
+ /**
312
+ * Get cookies response hash
313
+ *
314
+ * @return array
315
+ */
316
+ public function getCookies()
317
+ {
318
+ if(empty($this->_responseHeaders['Set-Cookie'])) {
319
+ return array();
320
+ }
321
+ $out = array();
322
+ foreach( $this->_responseHeaders['Set-Cookie'] as $row) {
323
+ $values = explode("; ", $row);
324
+ $c = count($values);
325
+ if(!$c) {
326
+ continue;
327
+ }
328
+ list($key, $val) = explode("=", $values[0]);
329
+ if(is_null($val)) {
330
+ continue;
331
+ }
332
+ $out[trim($key)] = trim($val);
333
+ }
334
+ return $out;
335
+ }
336
+
337
+
338
+ /**
339
+ * Get cookies array with details
340
+ * (domain, expire time etc)
341
+ * @return array
342
+ */
343
+ public function getCookiesFull()
344
+ {
345
+ if(empty($this->_responseHeaders['Set-Cookie'])) {
346
+ return array();
347
+ }
348
+ $out = array();
349
+ foreach( $this->_responseHeaders['Set-Cookie'] as $row) {
350
+ $values = explode("; ", $row);
351
+ $c = count($values);
352
+ if(!$c) {
353
+ continue;
354
+ }
355
+ list($key, $val) = explode("=", $values[0]);
356
+ if(is_null($val)) {
357
+ continue;
358
+ }
359
+ $out[trim($key)] = array('value'=>trim($val));
360
+ array_shift($values);
361
+ $c--;
362
+ if(!$c) {
363
+ continue;
364
+ }
365
+ for($i = 0; $i<$c; $i++) {
366
+ list($subkey, $val) = explode("=", $values[$i]);
367
+ $out[trim($key)][trim($subkey)] = trim($val);
368
+ }
369
+ }
370
+ return $out;
371
+ }
372
+
373
+ /**
374
+ * Process response headers
375
+ */
376
+ protected function processResponseHeaders()
377
+ {
378
+ $crlf = "\r\n";
379
+ $this->_responseHeaders = array();
380
+ while (!feof($this->_sock)) {
381
+ $line = fgets($this->_sock, 1024);
382
+ if($line === $crlf) {
383
+ return;
384
+ }
385
+ $name = $value = '';
386
+ $out = explode(": ", trim($line), 2);
387
+ if(count($out) == 2) {
388
+ $name = $out[0];
389
+ $value = $out[1];
390
+ }
391
+ if(!empty($value)) {
392
+ if($name == "Set-Cookie") {
393
+ if(!isset($this->_responseHeaders[$name])) {
394
+ $this->_responseHeaders[$name] = array();
395
+ }
396
+ $this->_responseHeaders[$name][] = $value;
397
+ } else {
398
+ $this->_responseHeaders[$name] = $value;
399
+ }
400
+ }
401
+ }
402
+ }
403
+
404
+ /**
405
+ * Process response body
406
+ */
407
+ protected function processResponseBody()
408
+ {
409
+ $this->_responseBody = '';
410
+
411
+ while (!feof($this->_sock)) {
412
+ $this->_responseBody .= @fread($this->_sock, 1024);
413
+ }
414
+ }
415
+
416
+ /**
417
+ * Process response
418
+ */
419
+ protected function processResponse()
420
+ {
421
+ $response = '';
422
+ $responseLine = trim(fgets($this->_sock, 1024));
423
+
424
+ $line = explode(" ", $responseLine, 3);
425
+ if(count($line) != 3) {
426
+ return $this->doError("Invalid response line returned from server: ".$responseLine);
427
+ }
428
+ $this->_responseStatus = intval($line[1]);
429
+ $this->processResponseHeaders();
430
+
431
+ $this->processRedirect();
432
+
433
+ $this->processResponseBody();
434
+ }
435
+
436
+
437
+ /**
438
+ * Process redirect
439
+ */
440
+ protected function processRedirect()
441
+ {
442
+ // TODO: implement redircets support
443
+ }
444
+
445
+
446
+ /**
447
+ * Get response status code
448
+ * @see lib/Mage/HTTP/Mage_HTTP_Client#getStatus()
449
+ */
450
+ public function getStatus()
451
+ {
452
+ return $this->_responseStatus;
453
+ }
454
+
455
+ /**
456
+ * Make request
457
+ * @param string $method
458
+ * @param string $uri
459
+ * @param array $params
460
+ * @return null
461
+ */
462
+ protected function makeRequest($method, $uri, $params = array())
463
+ {
464
+ $errno = $errstr = '';
465
+ $this->_sock = @fsockopen($this->_host, $this->_port, $errno, $errstr, $this->_timeout);
466
+ if(!$this->_sock) {
467
+ return $this->doError(sprintf("[errno: %d] %s", $errno, $errstr));
468
+ }
469
+
470
+ $crlf = "\r\n";
471
+ $isPost = $method == "POST";
472
+
473
+ $appendHeaders = array();
474
+ $paramsStr = false;
475
+ if($isPost && count($params)) {
476
+ $paramsStr = http_build_query($params);
477
+ $appendHeaders['Content-type'] = 'application/x-www-form-urlencoded';
478
+ $appendHeaders['Content-length'] = strlen($paramsStr);
479
+ }
480
+
481
+ $out = "{$method} {$uri} HTTP/1.1{$crlf}";
482
+ $out .= $this->headersToString($appendHeaders);
483
+ $out .= $crlf;
484
+ if($paramsStr) {
485
+ $out .= $paramsStr.$crlf;
486
+ }
487
+
488
+ fwrite($this->_sock, $out);
489
+ $this->processResponse();
490
+ }
491
+
492
+ /**
493
+ * Throw error excpetion
494
+ * @param $string
495
+ * @throws Exception
496
+ */
497
+ public function doError($string)
498
+ {
499
+ throw new Exception($string);
500
+ }
501
+
502
+ /**
503
+ * Convert headers hash to string
504
+ * @param $delimiter
505
+ * @param $append
506
+ * @return string
507
+ */
508
+ protected function headersToString($append = array())
509
+ {
510
+ $headers = array();
511
+ $headers["Host"] = $this->_host;
512
+ $headers['Connection'] = "close";
513
+ $headers = array_merge($headers, $this->_headers, $append);
514
+ $str = array();
515
+ foreach ($headers as $k=>$v) {
516
+ $str []= "$k: $v\r\n";
517
+ }
518
+ return implode($str);
519
+ }
520
+
521
+ /**
522
+ * TODO
523
+ */
524
+ public function setOptions($arr)
525
+ {
526
+ // Stub
527
+ }
528
+
529
+ /**
530
+ * TODO
531
+ */
532
+ public function setOption($name, $value)
533
+ {
534
+ // Stub
535
+ }
536
+
537
+ }
downloader/lib/Mage/HTTP/IClient.php ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_HTTP
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Interface for different HTTP clients
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Connect
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ interface Mage_HTTP_IClient
35
+ {
36
+ /**
37
+ * Set request timeout
38
+ * @param int $value
39
+ */
40
+ function setTimeout($value);
41
+
42
+
43
+ /**
44
+ * Set request headers from hash
45
+ * @param array $headers
46
+ */
47
+ function setHeaders($headers);
48
+
49
+ /**
50
+ * Add header to request
51
+ * @param string $name
52
+ * @param string $value
53
+ */
54
+ function addHeader($name, $value);
55
+
56
+
57
+ /**
58
+ * Remove header from request
59
+ * @param string $name
60
+ */
61
+ function removeHeader($name);
62
+
63
+
64
+ /**
65
+ * Set login credentials
66
+ * for basic auth.
67
+ * @param string $login
68
+ * @param string $pass
69
+ */
70
+ function setCredentials($login, $pass);
71
+
72
+ /**
73
+ * Add cookie to request
74
+ * @param string $name
75
+ * @param string $value
76
+ */
77
+ function addCookie($name, $value);
78
+
79
+ /**
80
+ * Remove cookie from request
81
+ * @param string $name
82
+ */
83
+ function removeCookie($name);
84
+
85
+ /**
86
+ * Set request cookies from hash
87
+ * @param array $cookies
88
+ */
89
+ function setCookies($cookies);
90
+
91
+ /**
92
+ * Remove cookies from request
93
+ */
94
+ function removeCookies();
95
+
96
+ /**
97
+ * Make GET request
98
+ * @param string full uri
99
+ */
100
+ function get($uri);
101
+
102
+ /**
103
+ * Make POST request
104
+ * @param string $uri full uri
105
+ * @param array $params POST fields array
106
+ */
107
+ function post($uri, $params);
108
+
109
+ /**
110
+ * Get response headers
111
+ * @return array
112
+ */
113
+ function getHeaders();
114
+
115
+ /**
116
+ * Get response body
117
+ * @return string
118
+ */
119
+ function getBody();
120
+
121
+ /**
122
+ * Get response status code
123
+ * @return int
124
+ */
125
+ function getStatus();
126
+
127
+ /**
128
+ * Get response cookies (k=>v)
129
+ * @return array
130
+ */
131
+ function getCookies();
132
+
133
+ /**
134
+ * Set additional option
135
+ * @param string $key
136
+ * @param string $value
137
+ */
138
+ function setOption($key, $value);
139
+
140
+ /**
141
+ * Set additional options
142
+ * @param array $arr
143
+ */
144
+ function setOptions($arr);
145
+ }
downloader/lib/Mage/System/Args.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_System
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Command-line options parsing class.
29
+ */
30
+ class Mage_System_Args
31
+ {
32
+ public $flags;
33
+ public $filtered;
34
+
35
+ /**
36
+ * Get flags/named options
37
+ * @return array
38
+ */
39
+ public function getFlags()
40
+ {
41
+ return $this->flags;
42
+ }
43
+
44
+ /**
45
+ * Get filtered args
46
+ * @return array
47
+ */
48
+ public function getFiltered()
49
+ {
50
+ return $this->filtered;
51
+ }
52
+
53
+ /**
54
+ * Constructor
55
+ * @param array $argv, if false $GLOBALS['argv'] is taken
56
+ * @return void
57
+ */
58
+ public function __construct($source = false)
59
+ {
60
+ $this->flags = array();
61
+ $this->filtered = array();
62
+
63
+ if(false === $source) {
64
+ $argv = $GLOBALS['argv'];
65
+ array_shift($argv);
66
+ }
67
+
68
+ for($i = 0, $iCount = count($argv); $i < $iCount; $i++)
69
+ {
70
+ $str = $argv[$i];
71
+
72
+ // --foo
73
+ if(strlen($str) > 2 && substr($str, 0, 2) == '--')
74
+ {
75
+ $str = substr($str, 2);
76
+ $parts = explode('=', $str);
77
+ $this->flags[$parts[0]] = true;
78
+
79
+ // Does not have an =, so choose the next arg as its value
80
+ if(count($parts) == 1 && isset($argv[$i + 1]) && preg_match('/^--?.+/', $argv[$i + 1]) == 0)
81
+ {
82
+ $this->flags[$parts[0]] = $argv[$i + 1];
83
+ $argv[$i + 1] = null;
84
+ }
85
+ elseif(count($parts) == 2) // Has a =, so pick the second piece
86
+ {
87
+ $this->flags[$parts[0]] = $parts[1];
88
+ }
89
+ }
90
+ elseif(strlen($str) == 2 && $str[0] == '-') // -a
91
+ {
92
+ $this->flags[$str[1]] = true;
93
+ if(isset($argv[$i + 1]) && preg_match('/^--?.+/', $argv[$i + 1]) == 0) {
94
+ $this->flags[$str[1]] = $argv[$i + 1];
95
+ $argv[$i + 1] = null;
96
+ }
97
+ } else if(!is_null($str)) {
98
+ $this->filtered[] = $str;
99
+ }
100
+ }
101
+ }
102
+ }
downloader/lib/Mage/System/Dirs.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_System
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+ class Mage_System_Dirs
27
+ {
28
+
29
+ public static function rm($dirname)
30
+ {
31
+ if(is_array($dirname)) {
32
+ $dirname = $dirname[1];
33
+ }
34
+ // Sanity check
35
+ if (!@file_exists($dirname)) {
36
+ return false;
37
+ }
38
+
39
+ // Simple delete for a file
40
+ if (@is_file($dirname) || @is_link($dirname)) {
41
+ return unlink($dirname);
42
+ }
43
+
44
+ // Create and iterate stack
45
+ $stack = array($dirname);
46
+ while ($entry = array_pop($stack)) {
47
+ // Watch for symlinks
48
+ if (@is_link($entry)) {
49
+ @unlink($entry);
50
+ continue;
51
+ }
52
+
53
+ // Attempt to remove the directory
54
+ if (@rmdir($entry)) {
55
+ continue;
56
+ }
57
+
58
+ // Otherwise add it to the stack
59
+ $stack[] = $entry;
60
+ $dh = opendir($entry);
61
+ while (false !== $child = readdir($dh)) {
62
+ // Ignore pointers
63
+ if ($child === '.' || $child === '..') {
64
+ continue;
65
+ }
66
+ // Unlink files and add directories to stack
67
+ $child = $entry . DIRECTORY_SEPARATOR . $child;
68
+ if (is_dir($child) && !is_link($child)) {
69
+ $stack[] = $child;
70
+ } else {
71
+ @unlink($child);
72
+ }
73
+ }
74
+ @closedir($dh);
75
+ }
76
+ return true;
77
+ }
78
+
79
+
80
+ public static function mkdirStrict($path, $recursive = true, $mode = 0777)
81
+ {
82
+ $exists = file_exists($path);
83
+ if($exists && is_dir($path)) {
84
+ return true;
85
+ }
86
+ if($exists && !is_dir($path)) {
87
+ throw new Exception("'{$path}' already exists, should be a dir, not a file!");
88
+ }
89
+ $out = @mkdir($path, $mode, $recursive);
90
+ if(false === $out) {
91
+ throw new Exception("Can't create dir: '{$path}'");
92
+ }
93
+ return true;
94
+ }
95
+
96
+ public static function copyFileStrict($source, $dest)
97
+ {
98
+ $exists = file_exists($source);
99
+ if(!$exists) {
100
+ throw new Exception('No file exists: '.$exists);
101
+ }
102
+
103
+ }
104
+ }
downloader/lib/Mage/Xml/Generator.php ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Xml
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+ class Mage_Xml_Generator
27
+ {
28
+ protected $_dom = null;
29
+ protected $_currentDom;
30
+
31
+ public function __construct()
32
+ {
33
+ $this->_dom = new DOMDocument('1.0');
34
+ $this->_dom->formatOutput=true;
35
+ $this->_currentDom = $this->_dom;
36
+ return $this;
37
+ }
38
+
39
+ public function getDom()
40
+ {
41
+ return $this->_dom;
42
+ }
43
+
44
+ protected function _getCurrentDom()
45
+ {
46
+ return $this->_currentDom;
47
+ }
48
+
49
+ protected function _setCurrentDom($node)
50
+ {
51
+ $this->_currentDom = $node;
52
+ return $this;
53
+ }
54
+
55
+ /**
56
+ * @param array $content
57
+ */
58
+ public function arrayToXml($content)
59
+ {
60
+ $parentNode = $this->_getCurrentDom();
61
+ if(!$content || !count($content)) {
62
+ return $this;
63
+ }
64
+ foreach ($content as $_key=>$_item) {
65
+ try{
66
+ $node = $this->getDom()->createElement($_key);
67
+ } catch (DOMException $e) {
68
+ // echo $e->getMessage();
69
+ var_dump($_item);
70
+ die;
71
+ }
72
+ $parentNode->appendChild($node);
73
+ if (is_array($_item) && isset($_item['_attribute'])) {
74
+ if (is_array($_item['_value'])) {
75
+ if (isset($_item['_value'][0])) {
76
+ foreach($_item['_value'] as $_k=>$_v) {
77
+ $this->_setCurrentDom($node)->arrayToXml($_v);
78
+ }
79
+ } else {
80
+ $this->_setCurrentDom($node)->arrayToXml($_item['_value']);
81
+ }
82
+ } else {
83
+ $child = $this->getDom()->createTextNode($_item['_value']);
84
+ $node->appendChild($child);
85
+ }
86
+ foreach($_item['_attribute'] as $_attributeKey=>$_attributeValue) {
87
+ $node->setAttribute($_attributeKey, $_attributeValue);
88
+ }
89
+ } elseif (is_string($_item)) {
90
+ $text = $this->getDom()->createTextNode($_item);
91
+ $node->appendChild($text);
92
+ } elseif (is_array($_item) && !isset($_item[0])) {
93
+ $this->_setCurrentDom($node)->arrayToXml($_item);
94
+ } elseif (is_array($_item) && isset($_item[0])) {
95
+ foreach($_item as $k=>$v) {
96
+ $this->_setCurrentDom($node)->arrayToXml($v);
97
+ }
98
+ }
99
+ }
100
+ return $this;
101
+ }
102
+
103
+ public function __toString()
104
+ {
105
+ return $this->getDom()->saveXML();
106
+ }
107
+
108
+ public function save($file)
109
+ {
110
+ $this->getDom()->save($file);
111
+ return $this;
112
+ }
113
+
114
+ }
downloader/lib/Mage/Xml/Parser.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Xml
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+ class Mage_Xml_Parser
27
+ {
28
+ protected $_dom = null;
29
+ protected $_currentDom;
30
+ protected $_content = array();
31
+
32
+ public function __construct()
33
+ {
34
+ $this->_dom = new DOMDocument;
35
+ $this->_currentDom = $this->_dom;
36
+ return $this;
37
+ }
38
+
39
+ public function getDom()
40
+ {
41
+ return $this->_dom;
42
+ }
43
+
44
+ protected function _getCurrentDom()
45
+ {
46
+ return $this->_currentDom;
47
+ }
48
+
49
+ protected function _setCurrentDom($node)
50
+ {
51
+ $this->_currentDom = $node;
52
+ return $this;
53
+ }
54
+
55
+ public function xmlToArray()
56
+ {
57
+ $this->_content = $this->_xmlToArray();
58
+ return $this->_content;
59
+ }
60
+
61
+ protected function _xmlToArray($currentNode=false)
62
+ {
63
+ if (!$currentNode) {
64
+ $currentNode = $this->getDom();
65
+ }
66
+ $content = array();
67
+ foreach ($currentNode->childNodes as $node) {
68
+ switch ($node->nodeType) {
69
+ case XML_ELEMENT_NODE:
70
+
71
+ $value = null;
72
+ if ($node->hasChildNodes()) {
73
+ $value = $this->_xmlToArray($node);
74
+ }
75
+ $attributes = array();
76
+ if ($node->hasAttributes()) {
77
+ foreach($node->attributes as $attribute) {
78
+ $attributes += array($attribute->name=>$attribute->value);
79
+ }
80
+ $value = array('_value'=>$value, '_attribute'=>$attributes);
81
+ }
82
+ if (isset($content[$node->nodeName])) {
83
+ if (!isset($content[$node->nodeName][0]) || !is_array($content[$node->nodeName][0])) {
84
+ $oldValue = $content[$node->nodeName];
85
+ $content[$node->nodeName] = array();
86
+ $content[$node->nodeName][] = $oldValue;
87
+ }
88
+ $content[$node->nodeName][] = $value;
89
+ } else {
90
+ $content[$node->nodeName] = $value;
91
+ }
92
+ break;
93
+ case XML_TEXT_NODE:
94
+ if (trim($node->nodeValue)) {
95
+ $content = $node->nodeValue;
96
+ }
97
+ break;
98
+ }
99
+ }
100
+ return $content;
101
+ }
102
+
103
+ public function load($file)
104
+ {
105
+ $this->getDom()->load($file);
106
+ return $this;
107
+ }
108
+
109
+ public function loadXML($string)
110
+ {
111
+ $this->getDom()->loadXML($string);
112
+ return $this;
113
+ }
114
+
115
+ }
downloader/mage.php ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Connect
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ define('DS', DIRECTORY_SEPARATOR);
28
+ define('PS', PATH_SEPARATOR);
29
+ define('BP', dirname(dirname(__FILE__)));
30
+ define('MAGENTO_ROOT', dirname(dirname(__FILE__)));
31
+
32
+ class __cli_Mage_Connect
33
+ {
34
+ private static $_instance;
35
+ protected $argv;
36
+ public static function instance()
37
+ {
38
+ if(!self::$_instance) {
39
+ self::$_instance = new self();
40
+ }
41
+ return self::$_instance;
42
+ }
43
+
44
+ public function init($argv)
45
+ {
46
+ $this->argv = $argv;
47
+ $this->setIncludes();
48
+ require_once("Mage/Autoload/Simple.php");
49
+ Mage_Autoload_Simple::register();
50
+ chdir(BP . DS . 'downloader' . DS);
51
+ return $this;
52
+ }
53
+
54
+ public function setIncludes()
55
+ {
56
+ if (defined('DEVELOPMENT_MODE')) {
57
+ $libPath = PS . dirname(BP) . DS . 'lib';
58
+ } else {
59
+ $libPath = PS . BP . DS . 'downloader' . DS . 'lib';
60
+ }
61
+ $includePath = BP . DS . 'app'
62
+ . $libPath
63
+ . PS . get_include_path();
64
+ set_include_path($includePath);
65
+ }
66
+
67
+
68
+
69
+ public function getCommands()
70
+ {
71
+ return Mage_Connect_Command::getCommands();
72
+ }
73
+
74
+ public function getFrontend()
75
+ {
76
+ $frontend = Mage_Connect_Frontend::getInstance('CLI');
77
+ Mage_Connect_Command::setFrontendObject($frontend);
78
+ return $frontend;
79
+ }
80
+
81
+ public function getConfig($fileName = 'connect.cfg')
82
+ {
83
+ if (isset($this->config)) {
84
+ return $this->config;
85
+ }
86
+ $config = new Mage_Connect_Config($fileName);
87
+ if (empty($config->magento_root)) {
88
+ $config->magento_root = dirname(dirname(__FILE__));
89
+ }
90
+ Mage_Connect_Command::setConfigObject($config);
91
+ $this->config = $config;
92
+ return $config;
93
+ }
94
+
95
+ public function detectCommand()
96
+ {
97
+ $argv = $this->argv;
98
+ if(empty($argv[1])) {
99
+ return false;
100
+ }
101
+ if(in_array($argv[1], $this->validCommands)) {
102
+ list($options,$params) = $this->parseCommandArgs($argv);
103
+ return array('name' => strtolower($argv[1]), 'options'=>$options, 'params'=>$params);
104
+ }
105
+ return false;
106
+ }
107
+
108
+ public function parseCommandArgs($argv)
109
+ {
110
+ $a = new Mage_System_Args();
111
+ $args = $a->getFiltered();
112
+ array_shift($args);
113
+ return array($a->getFlags(), $args);
114
+ }
115
+
116
+ public function runCommand($cmd, $options, $params)
117
+ {
118
+ $c = Mage_Connect_Command::getInstance($cmd);
119
+ $c->run($cmd, $options, $params);
120
+ }
121
+
122
+ private $_sconfig;
123
+ public function getSingleConfig()
124
+ {
125
+ if(!$this->_sconfig) {
126
+ $this->_sconfig = new Mage_Connect_Singleconfig(
127
+ $this->getConfig()->magento_root . DS .
128
+ $this->getConfig()->downloader_path . DS .
129
+ Mage_Connect_Singleconfig::DEFAULT_SCONFIG_FILENAME
130
+ );
131
+ }
132
+ Mage_Connect_Command::setSconfig($this->_sconfig);
133
+ return $this->_sconfig;
134
+ }
135
+
136
+ public function run()
137
+ {
138
+ $this->commands = $this->getCommands();
139
+ $this->frontend = $this->getFrontend();
140
+ $this->config = $this->getConfig();
141
+ $this->validCommands = array_keys($this->commands);
142
+ $this->getSingleConfig();
143
+ $cmd = $this->detectCommand();
144
+ if(!$cmd) {
145
+ $this->frontend->outputCommandList($this->commands);
146
+ } else {
147
+ $this->runCommand($cmd['name'], $cmd['options'], $cmd['params']);
148
+ }
149
+
150
+ }
151
+
152
+ }
153
+
154
+ if (defined('STDIN') && defined('STDOUT') && (defined('STDERR'))) {
155
+ __cli_Mage_Connect::instance()->init($argv)->run();
156
+ }
downloader/skin/boxes.css ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default
22
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+ /*
26
+ RESET
27
+ ******************************************************/
28
+ * { margin:0; padding:0; }
29
+ body { background:#f6f6f6; color:#2f2f2f; font:12px/1.55em arial, helvetica; }
30
+ a { color:#ea7601; }
31
+ a:hover { color:#d56b00; }
32
+ p { margin-bottom:1em; }
33
+ th { font-weight:bold; }
34
+ fieldset { border:none; }
35
+ form { display:inline; }
36
+ input, select, button { vertical-align:middle; }
37
+ li { list-style:none; }
38
+
39
+ /* COMMON ELEMENTS
40
+ ******************************************************/
41
+
42
+ /* Messages */
43
+ .msgs ul { margin-bottom:14px; padding:4px 10px 3px 10px; }
44
+ .msgs li {
45
+ list-style:none;
46
+ margin:0 0 3px 0;
47
+ border:0;
48
+ padding:0;
49
+ font-size:.95em;
50
+ font-weight:bold;
51
+ }
52
+ .error-msg { color:#df280a !important; background:#faebe7; }
53
+ .success-msg { color:#3d6611; background:#eff5ea; }
54
+ .notice-msg { background:#fffbf0; color:#3d6611 !important; }
55
+ .warning-msg { background:#e6e6e6; color:#000000 !important; }
56
+
57
+
58
+
59
+ /* Forms */
60
+ .form-list { margin-bottom:10px; }
61
+ .form-list td.label { padding:2px 8px 2px 0; }
62
+ .form-list td.value { padding:2px 0 2px 8px; }
63
+ .form-btn-set { margin-top:10px; text-align:right; }
64
+ button, .form-btn {
65
+ border-width:1px;
66
+ border-style:solid;
67
+ border-color:#ed6502 #a04300 #a04300 #ed6502;
68
+ background:url(images/btn_bg.gif) #ffac47 repeat-x 0 100%;
69
+ padding:0 7px 1px 7px;
70
+ color:#fff;
71
+ font:bold 12px arial, helvetica, sans-serif;
72
+ cursor:pointer;
73
+ white-space:nowrap;
74
+ }
75
+ a.form-btn,
76
+ a.form-btn:hover { color:#fff; padding-top:1px; padding-bottom:2px; text-decoration:none; }
77
+
78
+
79
+ /* Heading */
80
+ .bar-head { margin-bottom:12px; background:#6f8992; padding:2px 8px; }
81
+ .bar-head h4 { float:left; margin:0; color:#fff; font-size:1em; }
82
+ .bar-head
83
+ .bar-head-btn { margin-right:-6px; position:relative; }
84
+
85
+
86
+ /* Lists */
87
+ .bare-list li { margin-bottom:8px; }
88
+ .disc { margin-bottom:12px; }
89
+ .disc li { margin-left:22px; list-style-type:disc; }
90
+ .divider { height:1px; margin:15px 0; background:#bbb; overflow:hidden; font-size:1px; line-height:0em; }
91
+
92
+
93
+ /*
94
+ BOXES
95
+ ******************************************************/
96
+
97
+ /* Base structure */
98
+ .container { width:750px; margin:35px auto 0 auto; }
99
+ .header-top { background:url(images/header_bg.gif) repeat-x #415d65; padding:25px 25px 10px 25px; }
100
+ .main {
101
+ min-height:400px;
102
+ border-width:0 1px 2px 1px;
103
+ border-color:#aeaeae #aeaeae #6a6a6a #aeaeae;
104
+ border-style:solid;
105
+ background:#fff;
106
+ }
107
+ .content { padding:10px 25px 35px 25px; }
108
+ .footer { width:710px; margin:0 auto 35px auto; padding:10px 20px; text-align:center; }
109
+
110
+
111
+ /* Header */
112
+ #logo {
113
+ width:329px;
114
+ height:31px;
115
+ background:url(images/logo.gif) no-repeat;
116
+ text-indent:-6000px;
117
+ }
118
+ .nav {
119
+ margin-bottom:20px;
120
+ padding:8px 15px 0 20px;
121
+ background:url(images/nav_bg.gif) repeat-x 0 100% #f6f6f6;
122
+ }
123
+ .nav li { list-style:none; float:left; }
124
+ .nav li a, .nav .nav li a:hover {
125
+ float:left;
126
+ margin-right:4px;
127
+ border:1px solid #ccc;
128
+ border-right-color:#999;
129
+ border-bottom:none;
130
+ background:#ccc;
131
+ padding:2px 11px;
132
+ color:#222;
133
+ text-decoration:none;
134
+ }
135
+ .nav li a.active, .nav li a.active:hover {
136
+ background:#fff;
137
+ color:#2f2f2f;
138
+ font-weight:bold;
139
+ text-decoration:none;
140
+ cursor:default;
141
+ }
142
+ .page-head { margin-bottom:14px; font-size:1.7em; font-weight:normal; }
143
+
144
+
145
+ /* Footer */
146
+ .footer .copyright { font-size:.95em; color:#444; }
147
+
148
+
149
+
150
+
151
+ /* SECTION-SPECIFIC
152
+ ******************************************************/
153
+
154
+ /* Connect Package */
155
+ .connect-packages table { table-layout:fixed; margin:6px 0; }
156
+ .connect-packages td,.connect-packages th {
157
+ padding:3px 5px;
158
+ border-right:solid 1px #ccc;
159
+ border-bottom:solid 1px #ccc;
160
+ background:#f6f6f6;
161
+ vertical-align:top;
162
+ word-wrap:break-word;
163
+ }
164
+ .connect-packages th { border-top:solid 1px #bbb; background:#ccc; text-align:left; }
165
+ .connect-packages td.first { border-left:solid 1px #bbb; }
166
+ .connect-packages td.last { border-right:solid 1px #bbb; }
167
+ .connect-packages tr.installed-latest td { background:#dbf1d7; }
168
+ .connect-packages tr.upgrade-available td { background:#fcfbbb; }
169
+ .connect-packages tr.stand-alone td { background:#cbe8fb; }
170
+ .connect-packages td .select { word-wrap:normal; width:100%; }
171
+ .step-count { background:#f77312; color:#fff; font-weight:bold; padding:0 4px; }
172
+
173
+
174
+
175
+
176
+ /* MISC
177
+ ******************************************************/
178
+
179
+ /* Clearing */
180
+ .bar-head:after,
181
+ .form-btn-set:after,
182
+ .nav:after,
183
+ .clear:after {
184
+ clear:both;
185
+ content:".";
186
+ display:block;
187
+ height:0;
188
+ font-size:0;
189
+ line-height:0;
190
+ visibility:hidden;
191
+ }
192
+
193
+
194
+ /* Directional and spacial */
195
+ .f-left { float:left; }
196
+ .f-right { float:right; }
197
+ .v-top { vertical-align:top; }
198
+ .v-middle { vertical-align:middle; }
199
+ .v-bottom { vertical-align:bottom; }
200
+ .a-left { text-align:left; }
201
+ .a-center { text-align:center !important; }
202
+ .a-right { text-align:right; }
203
+ .nm { margin:0 !important; }
204
+ .np { padding:0 !important; }
205
+ .no-display { display:none; }
206
+ .no-show { display:none; }
207
+ .no-br { white-space:nowrap; }
208
+ .no-float { float:none !important; }
209
+ .big { font-size:1.2em !important; }
210
+
211
+ .loading-mask { color:#d85909; font-size:1.1em; font-weight:bold; text-align:center; opacity:0.80; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; z-index:500; }
212
+ .loading-mask .loader { position:absolute; /* position:absolute; top:143px; */ left:50%; width:120px; margin-left:-120px; padding:15px 60px; background:#fff4e9; border:2px solid #f1af73; color:#d85909; font-weight:bold; text-align:center; z-index:1000; }
213
+
214
+ /* Settings Page */
215
+ .settings-page .form-list td { width:200px; }
216
+ .settings-page .form-list select { width:254px; }
217
+ .settings-page .form-list .input-text { width:250px; }
downloader/skin/ie7boxes.css ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default
22
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+ .main { height:auto !important; }
26
+ button, .form-button { filter:chroma(color=#000000); }
27
+ .connect-packages td .select { margin:0 0 2px; width:100%; }
downloader/skin/ieboxes.css ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default
22
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+ button, .form-button { filter:chroma(color=#000000); overflow:visible; width:auto; }
26
+ .main { height:400px; }
27
+ .nav, .form-btn-set, .header-top, .bar-head { zoom:1; }
28
+ .clear { clear:both; height:0; font-size:0; line-height:0; overflow:hidden; }
29
+ .connect-packages td .select { margin:0 0 2px; }
downloader/skin/images/Magento_Connect.jpg ADDED
Binary file
downloader/skin/images/ajax-loader-tr.gif ADDED
Binary file
downloader/skin/images/btn_bg.gif ADDED
Binary file
downloader/skin/images/header_bg.gif ADDED
Binary file
downloader/skin/images/logo.gif ADDED
Binary file
downloader/skin/images/nav_bg.gif ADDED
Binary file
downloader/skin/images/nav_separator.gif ADDED
Binary file
downloader/skin/install/boxes.css ADDED
@@ -0,0 +1,414 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default
22
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+
26
+ /****************************************************/
27
+ /***********[ Mage_CSS_B Common Elements ]***********/
28
+ /****************************************************/
29
+
30
+
31
+ /********************** Columns */
32
+
33
+ /* All */
34
+ .col2-set, .col3-set, .col4-set, .col5-set { clear:both; }
35
+
36
+ /* Col2 */
37
+ .col2-set .col-1, .col2-set .col-2 { width:48.5%; }
38
+ .col2-set .col-1 { float:left; }
39
+ .col2-set .col-2 { float:right;}
40
+
41
+ /* Col2-alt */
42
+ .col2-alt-set .col-1 { width:32%; }
43
+ .col2-alt-set .col-2 { width:65%; }
44
+ .col2-alt-set .col-1 { float:left; }
45
+ .col2-alt-set .col-2 { float:right;}
46
+
47
+ /* Col3 */
48
+ .col3-set .col-1, .col3-set .col-2, .col3-set .col-3 { float:left; width:31.3%; }
49
+ .col3-set .col-1, .col3-set .col-2 { margin-right:3%; }
50
+
51
+ /* Col4 */
52
+ .col4-set .col-1, .col4-set .col-2, .col4-set .col-3, .col4-set .col-4 { float:left; width:22%; }
53
+ .col4-set .col-1, .col4-set .col-2, .col4-set .col-3 { margin-right:4%; }
54
+
55
+ /* Table Columns */
56
+ table .col-1, table .col-2, table .col-3, table .col-4 { float:none !important; margin:0 !important; }
57
+ .col3-set td.spacer { width:3%; }
58
+ .col4-set td.spacer { width:4%; }
59
+
60
+
61
+
62
+ /********************** Form */
63
+
64
+ /* Form Elements */
65
+ input.input-text, select, textarea { border:1px solid #b6b6b6; font:12px arial, helvetica, sans-serif; }
66
+ option, optgroup { font:12px arial, helvetica, sans-serif; }
67
+ optgroup { font-weight:bold; }
68
+ input.input-text, textarea { padding:2px; }
69
+ input.form-radio { margin-right:3px;}
70
+ .qty { width:2.5em; }
71
+ .group-select label, .form-list label, .payment-methods label { font-weight:bold;}
72
+ .button-set { /* Container for form buttons*/
73
+ clear:both;
74
+ margin-top:4em;
75
+ border-top:1px solid #e4e4e4;
76
+ padding-top:8px;
77
+ text-align:right;
78
+ }
79
+ .form-button, .form-button-alt {
80
+ overflow:visible;
81
+ width:auto;
82
+ background-color:transparent;
83
+ border:0;
84
+ padding:1px 8px;
85
+ background:#f18200;
86
+ color:#fff;
87
+ border:1px solid #de5400;
88
+ font:bold 12px arial, sans-serif !important;
89
+ cursor:pointer;
90
+ text-align:center;
91
+ vertical-align:middle;
92
+ }
93
+ .form-button span, .form-button-alt span {
94
+ white-space:nowrap;
95
+ }
96
+ .form-button-alt {
97
+ border:1px solid #406a83;
98
+ background-color:#618499;
99
+ }
100
+
101
+ .fieldset-download .form-button { margin:0.8em 0 0; }
102
+
103
+
104
+ /* Form lists */
105
+ .form-list li { margin-bottom:6px; }
106
+ .form-list li .input-box .input-text, .form-list li .input-box textarea { width:250px; }
107
+ .form-list li .input-box select { width:256px;}
108
+
109
+ table.form-list td { padding:2px 5px 2px 0; width:225px; }
110
+ table.form-list input { width:248px; }
111
+ table.form-list select { width:254px; }
112
+
113
+ .group-select {
114
+ margin:28px 0;
115
+ border:1px solid #bbafa0;
116
+ padding:22px 25px 12px 25px;
117
+ background:#fbfaf6;
118
+ }
119
+ .group-select .legend {
120
+ margin-top:-33px;
121
+ float:left;
122
+ border:1px solid #f19900;
123
+ background:#F9F3E3;
124
+ padding:0 8px;
125
+ color:#E76200;
126
+ font-weight:bold;
127
+ font-size:1.1em;
128
+ }
129
+ .group-select li { padding:4px 8px !important; }
130
+ .group-select li .input-box { float:left; width:275px; }
131
+ .group-select li .input-text, .group-select li select, .group-select li textarea { width:525px; }
132
+ .group-select li .input-box .input-text, .group-select li .input-box textarea { width:250px; }
133
+ .group-select li .input-box select { width:256px;}
134
+
135
+
136
+ /* Form Messages */
137
+ .validation-advice, .required { color:#EB340A; }
138
+ .validation-advice {
139
+ clear:both;
140
+ min-height:15px;
141
+ margin-top:3px;
142
+ background:url(images/validation_advice_bg.gif) no-repeat 2px 1px;
143
+ padding-left:17px;
144
+ font-size:.95em;
145
+ font-weight:bold;
146
+ line-height:1.25em;
147
+ }
148
+ .validation-failed {
149
+ border:1px dashed #EB340A !important;
150
+ background:#faebe7 !important;
151
+ }
152
+ label.required {
153
+ font-weight:bold;
154
+ }
155
+ p.required {
156
+ font-size:.95em;
157
+ text-align:right;
158
+ }
159
+
160
+
161
+
162
+ /********************** Messages */
163
+ .success { color:#3d6611; }
164
+ .error { color:#df280a; }
165
+ .success, .error { font-weight:bold; }
166
+ .error-msg, .success-msg, .notice-msg, .note-msg {
167
+ min-height:23px !important;
168
+ margin-bottom:1em !important;
169
+ border-style:solid !important;
170
+ border-width:1px !important;
171
+ background-repeat:no-repeat !important;
172
+ background-position:10px 10px !important;
173
+ padding:8px 8px 8px 32px !important;
174
+ font-size:.95em !important;
175
+ font-weight:bold !important;
176
+ }
177
+ .error-msg li, .success-msg li, .notice-msg li {margin-bottom:.2em; }
178
+ .error-msg {
179
+ border-color:#f16048;
180
+ color:#df280a;
181
+ background-color:#faebe7;
182
+ background-image:url(images/error_msg_icon.gif);
183
+ }
184
+ .success-msg {
185
+ border-color:#446423;
186
+ color:#3d6611;
187
+ background-color:#eff5ea;
188
+ background-image:url(images/success_msg_icon.gif);
189
+ }
190
+ .notice-msg, .note-msg {
191
+ border-color:#fcd344;
192
+ color:#3d6611;
193
+ background-color:#fafaec;
194
+ background-image:url(images/note_msg_icon.gif);
195
+ }
196
+
197
+
198
+
199
+ /********************** Headings */
200
+
201
+ .head, .inner-head { line-height:1.25em; text-align:right; }
202
+ .head h1,.head h2, .head h3, .head h4, .head h5,
203
+ .inner-head h1,.inner-head h2, .inner-head h3, .inner-head h4, .inner-head h5{ margin:0; float:left; }
204
+
205
+
206
+ /* Page heading */
207
+ .page-head { margin:0 0 25px 0; border-bottom:1px solid #ccc; }
208
+ .page-head-alt { margin:0 0 12px 0; }
209
+ .page-head, .page-head-alt { text-align:right; }
210
+ .page-head h3, .page-head-alt h3 {
211
+ margin:0;
212
+ font-size:1.7em !important;
213
+ font-weight:normal !important;
214
+ text-transform:none !important;
215
+ text-align:left;
216
+ }
217
+ .button-level h3 { /* heading level with buttons */
218
+ float:left;
219
+ width:60%;
220
+ }
221
+
222
+
223
+ /* Category list heading */
224
+ .category-head {
225
+ margin-bottom:7px;
226
+ }
227
+ .category-head h2 {
228
+ margin:0;
229
+ padding:3px 0;
230
+ color:#0a263c;
231
+ font-size:1.6em;
232
+ line-height:1.3em;
233
+ font-weight:normal;
234
+ }
235
+
236
+
237
+
238
+
239
+ /********************** Lists */
240
+ .disc { margin-bottom:10px; }
241
+ .disc li { margin-left:20px; list-style:disc; }
242
+
243
+
244
+ /* Bare List */ /* Unstyled list */
245
+ .bare-list { margin:5px 0; }
246
+ .bare-list li { margin:3px 0; }
247
+
248
+
249
+
250
+ /********************** Space Creators */
251
+
252
+ .no-show { display:none; }
253
+ .no-wrap { white-space:nowrap; }
254
+ .content-box { min-height:250px; } /* Set minimum height for visual presentation */
255
+ .content { padding:12px 12px 12px 15px; } /* Sets default padding */
256
+ .actions { line-height:1.3em; }
257
+ .separator { padding:0 5px;}
258
+ .pipe { padding:0 4px; font-size:.95em; }
259
+ .divider {
260
+ margin:10px 0;
261
+ height:1px;
262
+ background:url(images/dotted_divider.gif) repeat-x;
263
+ font-size:1px;
264
+ line-height:1em;
265
+ overflow:hidden;
266
+ }
267
+
268
+
269
+
270
+
271
+ /************************************************************/
272
+ /********************[ Mage_CSS_C Layout]********************/
273
+ /************************************************************/
274
+
275
+
276
+ /********************** Base Layout */
277
+
278
+ /* Structure */
279
+ .header {
280
+ z-index:999;
281
+ text-align:left;
282
+ }
283
+ .header-top {
284
+ position:relative;
285
+ width:930px;
286
+ margin:0 auto;
287
+ }
288
+ .header-nav {
289
+ width:950px;
290
+ margin:0 auto;
291
+ }
292
+ .middle {
293
+ min-height:400px;
294
+ width:900px;
295
+ margin:0 auto;
296
+ text-align:left;
297
+ position:relative;
298
+ }
299
+ .side-col { width:195px; }
300
+ .col-left { float:left; }
301
+ .col-main { float:left; }
302
+ .col-right { float:right; }
303
+ .col-1-layout .col-main { float:none; margin:0; }
304
+ .col-2-right-layout .col-main { float:left; width:685px; }
305
+ .col-2-left-layout .col-main { float:right; width:685px; }
306
+ .col-3-layout .col-main { width:475px; margin-left:17px; }
307
+
308
+ /* Style */
309
+ .header { border-top:5px solid #0d2131; }
310
+ .header-top-container { border-bottom:1px solid #415966; background:url(images/header_top_container_bg.jpg) repeat-x 50% 0; }
311
+ .header-top { padding:10px; }
312
+ .header-nav-container { background:url(images/nav_bg.jpg) repeat-y 50% 0 #0a263d; }
313
+ .middle-container { background:url(images/main_container_bg.gif) no-repeat 50% 0 #fbfaf6; }
314
+ .middle { background:url(images/main_bg.gif) no-repeat #fffffe; padding:25px 25px 80px 25px; }
315
+
316
+
317
+
318
+ /********************** Header */
319
+
320
+ /* Logo */
321
+ h1#logo {
322
+ float:left;
323
+ width:202px;
324
+ margin:3px 0 10px 12px;
325
+ }
326
+ .page-popup h1#logo { display:none; }
327
+
328
+
329
+ /* Quick Access*/
330
+ .quick-access {
331
+ width:390px;
332
+ float:right;
333
+ margin-top:28px;
334
+ text-align:right;
335
+ padding:0 10px;
336
+ color:#fff;
337
+ }
338
+ .quick-access p { margin-bottom:4px; }
339
+ .quick-access li {
340
+ display:inline;
341
+ background:url(images/shop_access_pipe.gif) no-repeat 100% .35em;
342
+ padding-right:7px;
343
+ padding-left:3px;
344
+ }
345
+ .quick-access li.first { padding-left:0;}
346
+ .quick-access li.last { padding-right:0; background:none;}
347
+ .account-access p, .account-access ul, .account-access li { display:inline; color:#fff; }
348
+ .account-access a, .account-access a:hover { color:#e1f1fb; }
349
+ .account-access ul { padding-left:10px; font-size:.95em; }
350
+ .shop-access a, .shop-access a:hover { color:#ebbc58; font-size:.95em; }
351
+
352
+
353
+ /* Breadcrumbs */
354
+ .breadcrumbs { margin-bottom:13px; font-size:.95em; line-height:1.25em; }
355
+ .breadcrumbs li { display:inline; }
356
+
357
+
358
+
359
+ /********************** Footer */
360
+ .footer-container { border-top:15px solid #B6D1E2; }
361
+ .footer {
362
+ width:930px;
363
+ margin:0 auto;
364
+ padding:1em 1em 4em 1em;
365
+ position:relative;
366
+ }
367
+ .footer .store-switcher { display:inline; padding:0 10px 0 0; vertical-align:middle; }
368
+ .footer .informational label { color:#fff; font-weight:bold; padding-right:3px; }
369
+ .footer .informational ul {
370
+ display:inline;
371
+ }
372
+ .footer .informational li {
373
+ display:inline;
374
+ background:url(images/footer_info_separator.gif) no-repeat 100% 50%;
375
+ padding-right:8px;
376
+ padding-left:4px;
377
+ }
378
+ .footer .informational li.last { background:none; padding-right:0; }
379
+ .footer .informational a, .footer .informational a:hover { color:#fff; }
380
+ .footer .informational a { text-decoration:none; }
381
+ .footer .legality {
382
+ padding:13px 0;
383
+ color:#ecf3f6;
384
+ text-align:center;
385
+ }
386
+ .footer .legality a, .footer .legality a:hover { color:#ecf3f6; }
387
+
388
+
389
+ /************************************************************/
390
+ /******************[ Mage_CSS_F Overrides]*******************/
391
+ /************************************************************/
392
+
393
+
394
+ /* Alignment */
395
+ .v-top { vertical-align:top; }
396
+ .v-middle { vertical-align:middle; }
397
+ .v-bottom { vertical-align:bottom; }
398
+ .a-left { text-align:left; }
399
+ .a-center { text-align:center; }
400
+ .a-right { text-align:right; }
401
+ .left { float:left; }
402
+ .right { float:right !important; }
403
+
404
+ .normal-weight { font-weight:normal; }
405
+ .auto-width { width:auto;}
406
+
407
+ /* Link highlights */
408
+ .link-cart { color:#DC6809 !important; font-weight:bold !important;}
409
+ .link-remove { color:#646464 !important;}
410
+ .link-print { background:url(images/icon_printer.gif) no-repeat 0 2px; padding-left:23px; }
411
+
412
+
413
+ /* For Demo store only */
414
+ .demo-notice { margin:0; background:#d75f07; padding:5px 10px 6px 10px; color:#fff; line-height:1em; text-align:center; }
downloader/skin/install/clears.css ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default
22
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+
26
+ /****************************************************/
27
+ /****************[ Mage_CSS_B Clears ]***************/
28
+ /****************************************************/
29
+
30
+ .page-head:after,
31
+ .page-head-alt:after,
32
+ .clear:after,
33
+ .col2-set:after,
34
+ .col3-set:after,
35
+ .col4-set:after,
36
+ .col2-alt-set:after,
37
+ .head:after,
38
+ .inner-head:after,
39
+ .header-top:after,
40
+ .quick-access:after,
41
+ .header-nav:after,
42
+ #nav:after,
43
+ .middle:after,
44
+ .product-essential:after,
45
+ .button-set:after,
46
+ .actions:after,
47
+ .legend:after,
48
+ .form-list li:after,
49
+ .button-container:after,
50
+ .ratings:after,
51
+ .page-head:after,
52
+ .page-head-alt:after,
53
+ .group-select li:after,
54
+ .search-autocomplete li:after,
55
+ .side-col li:after,
56
+ .account-box li:after,
57
+ .address-list li:after,
58
+ .generic-product-list li:after,
59
+ .listing-type-list .listing-item:after,
60
+ .listing-type-list .product-info .product-reviews:after,
61
+ .my-review-detail:after {
62
+ content:".";
63
+ display:block;
64
+ clear:both;
65
+ height:0;
66
+ font-size:0;
67
+ line-height:0em;
68
+ visibility:hidden;
69
+ overflow:hidden;
70
+ }
downloader/skin/install/ie7minus.css ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default
22
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+
26
+ #nav li.parent { margin-bottom:-3px; }
27
+ .one-page-checkout { position:relative; }
28
+ .group-select .legend { position:relative; zoom:1; }
29
+
30
+ /* Min-height for IE */
31
+ .login-box .content { height:180px; }
32
+ .content-box { height:250px; }
33
+ #main { height:400px; }
34
+
35
+ .validation-advice { height:15px; }
36
+ .error-msg, .success-msg, .note-msg { height:23px; }
37
+ .currency-switcher h4 { height:21px; }
38
+ .base-mini .head h4, .shopping-cart-collaterals h4 { height:16px; }
39
+ .login-box h4 { height:16px; }
40
+ .login-box .content { height:230px; }
downloader/skin/install/iestyles.css ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default
22
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+ .col2-set,
26
+ .col3-set,
27
+ .col4-set,
28
+ .col2-alt-set,
29
+ .head,
30
+ .page-head,
31
+ .page-head-alt,
32
+ .header-top-container,
33
+ .header-top,
34
+ .header-nav-container,
35
+ .header-nav,
36
+ .quick-access,
37
+ #nav,
38
+ #nav li,
39
+ #nav a,
40
+ .middle,
41
+ .product-essential,
42
+ .button-set,
43
+ .actions,
44
+ .form-list li,
45
+ .button-container,
46
+ .ratings,
47
+ .page-head,
48
+ .page-head-alt,
49
+ .group-select li,
50
+ .search-autocomplete li,
51
+ .side-col li,
52
+ .account-box li,
53
+ .address-list li,
54
+ .listing-type-list .listing-item,
55
+ .listing-type-list .product-info .product-reviews,
56
+ .account-nav a,
57
+ .account-box,
58
+ .my-review-detail,
59
+ .generic-product-list li { zoom:1; }
60
+
61
+ .clear {
62
+ display:block;
63
+ clear:both;
64
+ height:0;
65
+ font-size:0;
66
+ line-height:0;
67
+ }
68
+ .multi-address-checkout-box .box { zoom:1; }
69
+ .multi-address-checkout-box .legend { zoom:1; position:relative; margin-left:8px;}
70
+ .quick-access li { padding-right:4px; padding-left:6px;}
71
+ .search-autocomplete { left:39px !important; }
72
+ .mini-search { padding-top:-1px; line-height:1em;}
73
+ .home-spot { display:inline; }
74
+ .mini-related-items .product-details { margin-left:76px; }
75
+ .mini-related-items .product-images input { float:left; margin:-4px 2px 0 -4px; }
76
+ .mini-related-items .product-images img { float:left; }
77
+ .header-top-container { position:relative; }
78
+ #nav ul li.parent { margin-bottom:-3px;}
downloader/skin/install/images/error_msg_icon.gif ADDED
Binary file
downloader/skin/install/images/footer_bg.gif ADDED
Binary file
downloader/skin/install/images/footer_container_bg.gif ADDED
Binary file
downloader/skin/install/images/footer_info_separator.gif ADDED
Binary file
downloader/skin/install/images/footer_informational_bg.gif ADDED
Binary file
downloader/skin/install/images/footer_left.gif ADDED
Binary file
downloader/skin/install/images/footer_legality_bg.gif ADDED
Binary file
downloader/skin/install/images/footer_right.gif ADDED
Binary file
downloader/skin/install/images/header_bg.gif ADDED
Binary file
downloader/skin/install/images/header_nav_bg.gif ADDED
Binary file
downloader/skin/install/images/header_top_bg.jpg ADDED
Binary file
downloader/skin/install/images/header_top_container_bg.jpg ADDED
Binary file
downloader/skin/install/images/logo.gif ADDED
Binary file
downloader/skin/install/images/main_bg.gif ADDED
Binary file
downloader/skin/install/images/main_container_bg.gif ADDED
Binary file
downloader/skin/install/images/note_msg_icon.gif ADDED
Binary file
downloader/skin/install/images/success_msg_icon.gif ADDED
Binary file
downloader/skin/install/images/validation_advice_bg.gif ADDED
Binary file
downloader/skin/install/reset.css ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Magento
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * that is bundled with this package in the file LICENSE_AFL.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to license@magentocommerce.com so we can send you a copy immediately.
13
+ *
14
+ * DISCLAIMER
15
+ *
16
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
17
+ * versions in the future. If you wish to customize Magento for your
18
+ * needs please refer to http://www.magentocommerce.com for more information.
19
+ *
20
+ * @category design
21
+ * @package default
22
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ */
25
+ /******************************************/
26
+ /***********[ Mage_CSS_A Reset ]***********/
27
+ /******************************************/
28
+
29
+ * { margin:0; padding:0; }
30
+
31
+ body {
32
+ background-color: #496778;
33
+ color:#2f2f2f;
34
+ font:12px/1.55em arial, helvetica, sans-serif;
35
+ text-align:center;
36
+ }
37
+
38
+ a { color:#1e7ec8; text-decoration:underline; }
39
+ a:hover { color:#1e7ec8; text-decoration:underline; }
40
+ a img { border:0;}
41
+
42
+ /* Heading */
43
+ h1, h2, h3, h4, h5, h6, .head {
44
+ margin-bottom:.4em;
45
+ line-height:1.3em;
46
+ color:#0A263C;
47
+ }
48
+ h2 { font-size:1.5em; }
49
+ h3 { font-size:1.35em; }
50
+ h4 { font-size:1.05em; }
51
+ h5 { font-size:1.05em; }
52
+ h6 { font-size:.95em; }
53
+
54
+ /* Table */
55
+ th { padding:0; text-align:left; vertical-align:top; }
56
+ td {padding:0;vertical-align:top;}
57
+
58
+ /* Paragraph */
59
+ p { margin-bottom:.8em; }
60
+ address { margin-bottom:.4em; }
61
+ address { font-style:normal; line-height:1.4em;}
62
+ cite { font-style:normal; font-size:10px;}
63
+ q:before, q:after{content:'';}
64
+
65
+ /* Form */
66
+ form { display:inline;}
67
+ fieldset { border:none; }
68
+ legend {display:none;}
69
+ label { color:#666; /*font-size:.95em;*/ font-weight:bold; }
70
+ input, select, button { vertical-align:middle; }
71
+
72
+ /* Lists */
73
+ dt { display:block; font-weight:bold; }
74
+ li { list-style:none; }
75
+
76
+ /* Size */
77
+ small { font-size:.9em; }
78
+ big { font-size:1.1em; }
79
+
80
+ hr { height:0; margin:8px 0; overflow:hidden; visibility:hidden; }
81
+ .nowrap { white-space:nowrap; }
82
+ :focus { outline: 0; }
83
+ .bold { font-weight:bold; }
downloader/template/.htaccess ADDED
@@ -0,0 +1,2 @@
 
 
1
+ Order deny,allow
2
+ Deny from all
downloader/template/connect/iframe.phtml ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <a name="connect_iframe"></a>
28
+
29
+ <div id="connect_iframe_container" style="display:none;">
30
+ <input id="connect_iframe_scroll" type="checkbox" checked="checked"/> <label for="connect_iframe_scroll">Auto-scroll console contents</label><br/>
31
+ <iframe id="connect_iframe" name="connect_iframe" src="<?php echo $this->url('empty') ?>" style="width:100%; height:300px;" frameborder="no"></iframe>
32
+ </div>
33
+
34
+ <script type="text/javascript">
35
+ function disableInputs(flag)
36
+ {
37
+ top.$$('input, select, button').each(function(el){
38
+ if (el.id!='connect_iframe_scroll') el.disabled = flag;
39
+ });
40
+ if (flag) {
41
+ window.onbeforeunload = confirmExit;
42
+ } else {
43
+ window.onbeforeunload = null;
44
+ }
45
+ }
46
+
47
+ function confirmExit()
48
+ {
49
+ return "There are Connect processes running.\nIf you will close the window or navigate away from the page, installation will be interrupted.";
50
+ }
51
+
52
+ function onSubmit(formObj)
53
+ {
54
+ if(formObj)formObj.action = addParamToUrl(formObj.action, 'maintenance', (top.$('maintenance').checked === true ? '1' : '0'));
55
+ top.$('connect_iframe_success').style.display = 'none';
56
+ top.$('connect_iframe_failure').style.display = 'none';
57
+ top.$('connect_iframe_container').style.display = '';
58
+ top.location.href = '#connect_iframe';
59
+ return true;
60
+ }
61
+
62
+ function onSuccess()
63
+ {
64
+ var div = top.$('connect_iframe_success');
65
+ if (div) {
66
+ top.location.href = top.location.href.replace(/#.*$/, '')+'#connect_iframe_result';
67
+ div.style.display = '';
68
+ }
69
+ }
70
+
71
+ function onFailure()
72
+ {
73
+ var div = top.$('connect_iframe_failure');
74
+ if (div) {
75
+ top.location.href = top.location.href.replace(/#.*$/, '')+'#connect_iframe_result';
76
+ div.style.display = '';
77
+ }
78
+ }
79
+
80
+ function checkForUpdateClick()
81
+ {
82
+ url = addParamToUrl(location.href, 'maintenance', (top.$('maintenance').checked === true ? '1' : '0'));
83
+ url = addParamToUrl(url, 'updates', 'yes');
84
+ location.href = url;
85
+ }
86
+
87
+ function addParamToUrl(url, param, value)
88
+ {
89
+ var anchor = null, params = {};
90
+ var anchorPos = url.search(/#/);
91
+ if (anchorPos != -1) {
92
+ anchor = url.substr(anchorPos + 1);
93
+ url = url.substr(0, anchorPos);
94
+ }
95
+ getPos = url.search(/\?/);
96
+ if (getPos != -1) {
97
+ url.substr(getPos + 1).split('&').each(function(pv){
98
+ if (pv != 'loggedin') {
99
+ pv = pv.split('=');
100
+ params[pv[0]] = pv[1];
101
+ }
102
+ });
103
+ url = url.substr(0, getPos);
104
+ }
105
+
106
+ params[param] = value;
107
+
108
+ if (params) {
109
+ url += '?';
110
+ for (k in params) {
111
+ url += k + '=' + params[k] + '&';
112
+ }
113
+ url = url.substr(0, url.length - 1);
114
+ }
115
+ if (anchor) {
116
+ url = url + '#' + anchor;
117
+ }
118
+
119
+ return url;
120
+ }
121
+ </script>
downloader/template/connect/packages.phtml ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php echo $this->template('header.phtml') ?>
28
+ <?php if ($this->get('writable_warning')) echo $this->template('writable.phtml');?>
29
+ <div class="bar-head">
30
+ <h4>Settings</h4>
31
+ </div>
32
+ <ul class="bare-list">
33
+ <li><input type="checkbox" id="maintenance" value="1" checked="checked" /> &nbsp;
34
+ <label for="maintenance">Put store on the maintenance mode while installing/upgrading</label>
35
+ </li>
36
+ </ul>
37
+
38
+ <div class="bar-head">
39
+ <h4>Install New Extensions</h4>
40
+ </div>
41
+ <script type="text/javascript">
42
+ <!--
43
+ function connectPrepare(form) {
44
+ new Ajax.Request(form.action, {
45
+ method:'post',
46
+ parameters: {install_package_id: form.install_package_id.value},
47
+ onCreate: function() {
48
+ $('prepare_package_result').update(
49
+ '<div class="loading-mask" id="loading_mask_loader">'+
50
+ ' <p class="loader">'+
51
+ ' <img src="<?php echo $this->baseUrl()?>/skin/images/ajax-loader-tr.gif" alt="Loading..."/><br/>Please wait...'+
52
+ ' </p>'+
53
+ '</div>'
54
+ );
55
+ $('loading_mask_loader').style.position = 'relative';
56
+ $('loading_mask_loader').top = 0;
57
+ $('prepare_package_result').show();
58
+ },
59
+ onSuccess: function(transport) {
60
+ // @TODO: check transport.status to show errors
61
+ $('prepare_package_result').update(transport.responseText);
62
+ $('prepare_package_result').show();
63
+ },
64
+ onFailure: function() {
65
+ $('prepare_package_result').update(
66
+ '<div id="packages_failure">' +
67
+ ' <ul class="msgs"> ' +
68
+ ' <li>' +
69
+ ' <ul class="error-msg">' +
70
+ ' <li>Connection Error try again later.</li>' +
71
+ ' </ul>' +
72
+ ' </li>' +
73
+ ' </ul>' +
74
+ '</div> '
75
+ );
76
+ }
77
+ });
78
+ return(false);
79
+ }
80
+ //-->
81
+ </script>
82
+ <form action="<?php echo $this->url('connectPreparePackagePost')?>" method="post" onsubmit="return connectPrepare(this)">
83
+ <ul class="bare-list">
84
+ <li>
85
+ <span class="step-count">1</span> &nbsp; Search for modules via <a href="http://connect.magentocommerce.com/" target="Magento_Connect">Magento Connect</a>.
86
+ </li>
87
+ <li>
88
+ <span class="step-count">2</span> &nbsp;
89
+ <label for="install_package_id">Paste extension key to install:</label> <input type="text" id="install_package_id" name="install_package_id" style="width:300px"/>
90
+ <button type="submit">Install</button>
91
+ </li>
92
+ </ul>
93
+ </form>
94
+
95
+ <br/>
96
+
97
+ <div class="connect-packages" id="prepare_package_result" style="display:none;"></div>
98
+ <br/>
99
+
100
+ <div class="bar-head">
101
+ <h4>Direct package file upload</h4>
102
+ </div>
103
+ <form action="<?php echo $this->url('connectInstallPackageUpload')?>" method="post" target="connect_iframe" onsubmit="onSubmit(this)" enctype="multipart/form-data">
104
+ <ul class="bare-list">
105
+ <li><span class="step-count">1</span> &nbsp; Download or build package file.</li>
106
+ <li>
107
+ <span class="step-count">2</span> &nbsp; Upload package file:
108
+ <label for="file"></label>
109
+ <input type="file" id="file" name="file"/>
110
+ <button type="submit">Upload</button>
111
+ </li>
112
+ </ul>
113
+ </form>
114
+
115
+ <br/><br/>
116
+ <div class="bar-head">
117
+ <h4>Manage Existing Extensions</h4>
118
+ <?php if (empty($_GET['updates'])): ?>
119
+ <span class="bar-head-btn f-right"><button type="button" class="f-right" onclick="checkForUpdateClick()">Check for Upgrades</button></span>
120
+ <?php endif; ?>
121
+ </div>
122
+ <?php $packages = $this->get('connect')->getAllInstalledPackages(); $i = 0; $cnt = count($packages); ?>
123
+ <?php $channelConfig=$this->get('channel_config');?>
124
+ <script type="text/javascript">
125
+ function formSubmit(id)
126
+ {
127
+ var formObj = $(id);
128
+ if (onSubmit(formObj)) {
129
+ formObj.submit();
130
+ }
131
+ }
132
+ </script>
133
+ <?php foreach ($packages as $channel=>$pkgs): ?>
134
+
135
+ <form id="connect_packages_<?php echo $i ?>" class="connect-packages" action="<?php echo $this->url('connectPackagesPost')?>" method="post" target="connect_iframe">
136
+ <div class="no-display">
137
+ <input type="hidden" id="ignore_local_modification" name="ignore_local_modification" value=""/>
138
+ <input type="hidden" name="form_id" value="connect_packages_<?php echo $i ?>"/>
139
+ </div>
140
+ <p class="nm"><button type="button" onclick="formSubmit('connect_packages_<?php echo $i ?>')" class="f-right">Commit Changes</button></p>
141
+ <h2 class="page-head">Channel: <?php echo $channelConfig->getChannelLabel($channel); ?></h2>
142
+ <p class="f-right"><label for="clean_sessions">Clear all sessions after successfull install or upgrade: <input type="checkbox" id="clean_sessions"/></label></p>
143
+ <div class="clear"></div>
144
+
145
+ <table cellspacing="0" cellpadding="0" width="100%">
146
+ <?php if (!empty($_GET['updates'])): ?>
147
+ <col width="190" />
148
+ <col width="60" />
149
+ <col width="60" />
150
+ <col width="160" />
151
+ <col width="170" />
152
+ <?php else: ?>
153
+ <col width="200" />
154
+ <col width="100" />
155
+ <col width="70" />
156
+ <col width="180" />
157
+ <?php endif; ?>
158
+ <thead>
159
+ <tr>
160
+ <th class="first">Package Name</th>
161
+ <th class="a-center">Installed</th>
162
+ <?php if (!empty($_GET['updates'])): ?><th class="a-center">Available</th><?php endif; ?>
163
+ <th>Actions</th>
164
+ <th class="last">Summary</th>
165
+ </tr>
166
+ </thead>
167
+ <tbody>
168
+ <?php foreach ($pkgs as $pkgName=>$pkg): ?>
169
+ <tr class="<?php echo $pkg['status']?>">
170
+ <td class="first"><?php echo $pkgName?></td>
171
+ <td class="a-center"><?php echo $pkg['version'].' ('.$pkg['stability'].')'?>&nbsp;</td>
172
+ <?php if (!empty($_GET['updates'])): ?><td class="a-center"><?php echo $pkg['upgrade_latest']?>&nbsp;</td><?php endif; ?>
173
+ <td><select class="select" name="actions[<?php echo $channel.'|'.$pkgName ?>]">
174
+ <option selected="selected"></option>
175
+ <?php if(isset($pkg['actions']) && is_array($pkg['actions'])): ?>
176
+ <?php foreach ($pkg['actions'] as $k=>$v): ?>
177
+ <option value="<?php echo $k ?>"><?php echo $v ?></option>
178
+ <?php endforeach; ?>
179
+ <?php endif; ?>
180
+ </select>
181
+ </td>
182
+ <td class="last"><?php echo $pkg['summary']?></td>
183
+ </tr>
184
+ <?php endforeach; /*channel*/ ?>
185
+ </tbody>
186
+ </table>
187
+ <div class="clear"></div>
188
+
189
+ <div class="form-btn-set">
190
+ <button type="button" onclick="formSubmit('connect_packages_<?php echo $i ?>')" class="f-right">Commit Changes</button>
191
+ <?php if (!empty($_GET['updates'])): ?>
192
+ <p class="f-left a-left">
193
+ <span style="background:#f6f6f6;padding:0 5px;">&nbsp;</span> &nbsp;Installed<br/>
194
+ <span style="background:#fcfbbb;padding:0 5px;">&nbsp;</span> &nbsp;Upgrade Available<br/>
195
+ </p>
196
+ <?php endif; ?>
197
+ </div>
198
+ </form>
199
+ <script type="text/javascript">
200
+ $$('#connect_packages_' + <?php echo $i?> + ' select').each(function(el){el.value=''});
201
+ </script>
202
+ <?php if (++$i != $cnt): ?><div class="divider"></div><?php endif ?>
203
+ <br/>
204
+ <?php endforeach; /*all packages*/ ?>
205
+
206
+
207
+ <?php echo $this->template('connect/iframe.phtml') ?>
208
+
209
+ <a name="connect_iframe_result"></a>
210
+ <div id="connect_iframe_success" style="display:none">
211
+ <?php $this->set('messages', array('success'=>array('Procedure completed. Please check the output frame for useful information and refresh the page to see changes.'))) ?>
212
+ <?php echo $this->template('messages.phtml') ?>
213
+ <button onclick="location.href='<?php echo $this->baseUrl() ?>'">Refresh</button>
214
+ </div>
215
+ <div id="connect_iframe_failure" style="display:none">
216
+ <?php $this->set('messages', array('error'=>array('Please check the output frame for errors and refresh the page to retry changes.'))) ?>
217
+ <?php echo $this->template('messages.phtml') ?>
218
+ <button onclick="location.href='<?php echo $this->baseUrl() ?>'">Refresh</button>
219
+ </div>
220
+
221
+ <?php echo $this->template('footer.phtml') ?>
downloader/template/connect/packages_prepare.phtml ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php
28
+ $packages = $this->get('packages');
29
+ $errors = $this->get('errors');
30
+ $cnt = count($packages);
31
+ if($cnt):
32
+ ?>
33
+ Extension dependencies
34
+ <form action="<?php
35
+ echo $this->url('connectInstallPackagePost')?>" method="post" target="connect_iframe" onsubmit="onSubmit(this)">
36
+ <input type="hidden" name="install_package_id" value="<?php echo $this->get('package_id'); ?>">
37
+ <table cellspacing="0" cellpadding="0" width="100%">
38
+ <col width="150" />
39
+ <col width="250" />
40
+ <col width="150" />
41
+ <col width="100" />
42
+ <thead>
43
+ <tr>
44
+ <th class="first">Channel</th>
45
+ <th class="first">Package Name</th>
46
+ <th>Version</th>
47
+ <th class="last">Status</th>
48
+ </tr>
49
+ </thead>
50
+ <tbody>
51
+ <?php foreach ($packages as $pkg): ?>
52
+ <tr class="<?php echo $pkg['status']?>">
53
+ <td class="first"><?php echo $pkg['channel']?></td>
54
+ <td><?php echo $pkg['name']?></td>
55
+ <td><?php echo $pkg['version'] . (!empty($pkg['stability']) ? ' (' . $pkg['stability'] . ')' : '')?></td>
56
+ <td class="last"><?php echo $pkg['message']?></td>
57
+ </tr>
58
+ <?php endforeach;?>
59
+ </tbody>
60
+ </table>
61
+ <div class="form-btn-set">
62
+ <button class="f-right" type="submit">Proceed</button>
63
+ <button class="f-right" style="margin-right:10px;" onclick="$('prepare_package_result').update();" type="reset">Cancel installation</button>
64
+ </div>
65
+ </form>
66
+ <?php
67
+ endif;
68
+ if (!$cnt || !empty($errors['error'])):
69
+ $_errors = array('error'=>array('Extension key is not valid.'));
70
+ if(!empty($errors) && is_array($errors)) $_errors = $errors;
71
+ $this->set('messages', $_errors)
72
+ ?>
73
+ <div id="packages_failure">
74
+ <?php echo $this->template('messages.phtml') ?>
75
+ </div>
76
+ <?php
77
+ endif;
78
+ ?>
downloader/template/exception.phtml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php echo $this->template($this->controller()->isInstalled() ? 'header.phtml' : 'install/header.phtml') ?>
28
+
29
+ <h2>Exception caught:</h2>
30
+ <br/>
31
+ <h3><?php echo $this->get('exception')->getMessage() ?></h3>
32
+ <br/>
33
+ <h4>Backtrace:</h4>
34
+ <pre><?php echo $this->get('exception')->getTraceAsString() ?></pre>
35
+
36
+ <?php echo $this->template($this->controller()->isInstalled() ? 'footer.phtml' : 'install/footer.phtml') ?>
downloader/template/footer.phtml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ </div>
28
+ </div>
29
+ </div>
30
+ <div class="footer">
31
+ <p class="copyright">
32
+ Help Us to Keep Magento Healthy - <a href="http://www.magentocommerce.com/bug-tracking" id="bug_tracking_link"><strong>Report All Bugs</strong></a> (Magento Connect Manager ver. <?php echo Maged_Controller::getVersion();?>)<br/>
33
+ <script type="text/javascript">
34
+ $('bug_tracking_link').target = "varien_external";
35
+ </script>
36
+ Magento is a trademark of Magento, Inc. Copyright © 2010 Magento Inc.
37
+ </p>
38
+ </div>
39
+ </body>
40
+ </html>
downloader/template/header.phtml ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
28
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
29
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
30
+ <head>
31
+ <title><?php echo $this->__('Magento Downloader') ?></title>
32
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
33
+ <link type="image/x-icon" href="<?php echo $this->baseUrl()?>/favicon.ico" rel="icon"/>
34
+ <link type="image/x-icon" href="<?php echo $this->baseUrl()?>/favicon.ico" rel="shortcut icon"/>
35
+ <script type="text/javascript" src="js/prototype.js"></script>
36
+ <link type="text/css" rel="stylesheet" href="skin/boxes.css"></link>
37
+ <!--[if IE]>
38
+ <link type="text/css" rel="stylesheet" href="skin/ieboxes.css" media="all"></link>
39
+ <![endif]-->
40
+ <!--[if gt IE 6]>
41
+ <link type="text/css" rel="stylesheet" href="skin/ie7boxes.css" media="all"></link>
42
+ <![endif]-->
43
+ </head>
44
+ <body>
45
+ <div class="container">
46
+
47
+ <div class="header-top">
48
+ <h1 id="logo">Magento Downloader</h1>
49
+ </div>
50
+ <div class="main">
51
+ <?php if ($this->controller()->getAction()!='login' && !$this->get('exception')): ?>
52
+ <div class="nav">
53
+ <?php if (true||$this->controller()->isWritable()): ?>
54
+ <?php if ($this->controller()->session()->getUserId()): ?>
55
+ <a href="<?php echo $this->url('logout') ?>" class="f-right" style="margin:0px 10px;">Log Out</a>
56
+ <?php if ($returnUrl = $this->controller()->session()->getReturnUrl()): ?>
57
+ <a href="<?php echo $returnUrl ?>" class="f-right" style="margin:0px 10px;">Return to Admin</a>
58
+ <?php endif; ?>
59
+ <?php endif; ?>
60
+ <ul>
61
+ <li class="first"><a <?php echo $this->getNavLinkParams('connectPackages') ?>>Extensions</a></li>
62
+ <li class="last"><a <?php echo $this->getNavLinkParams('settings') ?>>Settings</a></li>
63
+ </ul>
64
+ <?php else: ?>
65
+ <ul>
66
+ <li class="first last"><a class="active">Check Write Permissions</a></li>
67
+ </ul>
68
+ <?php endif; ?>
69
+ </div>
70
+ <?php endif; ?>
71
+ <div class="content">
72
+ <?php $this->set('messages', $this->controller()->session()->getMessages()) ?>
73
+ <?php echo $this->template('messages.phtml') ?>
downloader/template/index.phtml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php echo $this->template('header.phtml') ?>
28
+
29
+ <h2 class="page-head">Start Here</h2>
30
+ <p>Here is some explanation about PEAR. Suspendisse sapien urna, facilisis sed, pharetra ut, blandit nec, nulla. Vivamus ac dui. Morbi justo ipsum, bibendum sed, egestas sed, pharetra ut, ligula. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Integer quis sapien vel sem semper luctus. Vestibulum tristique venenatis velit. Ut urna nisl, dignissim vitae, cursus eget, pulvinar scelerisque, lectus. In ac leo id libero consequat dignissim. Sed aliquam est a pede. Phasellus ut turpis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed magna leo, volutpat eget, pretium tristique, varius vitae, tellus. Sed odio ante, sagittis id, euismod eu, bibendum quis, purus. Proin consectetuer elementum nunc. Mauris turpis. In sed eros eu enim sagittis viverra. Integer adipiscing vestibulum tortor. Proin ante. Vivamus euismod, tortor id condimentum condimentum, arcu odio posuere est, eu eleifend nunc nulla sed nibh. Proin pretium sapien vitae erat.<br/><a href="<?php echo $this->url('settings') ?>">Change your PEAR settings</a></p>
31
+
32
+ <p class="a-center"><a href="<?php echo $this->url('pearGlobal') ?>" class="form-btn">Proceed with complete Magento PEAR Download/Upgrade</a></p>
33
+ <p class="a-center"><a href="<?php echo $this->url('pearPackages') ?>" class="form-btn">Proceed to individual PEAR packages management</a></p>
34
+
35
+ <?php echo $this->template('footer.phtml') ?>
36
+
downloader/template/install/download.phtml ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php echo $this->template('install/header.phtml') ?>
28
+
29
+ <div class="page-head">
30
+ <h3>Welcome to Magento's Installation Wizard!</h3>
31
+ </div>
32
+
33
+ <?php if (!$this->controller()->isDownloaded()): ?>
34
+ <p>You are now ready to continue the installation process by downloading the most up-to-date copy of the Magento software.</p>
35
+ <?php echo($this->get('channel_notice')); ?>
36
+ <form id="install_all" method="post" action="<?php echo $this->url('connectInstallAll') ?>" target="connect_iframe" onsubmit="return installAll()">
37
+ <fieldset class="fieldset-download">
38
+ <?php else: ?>
39
+ <p>There's an indication that Magento files already have been downloaded.</p>
40
+ <p>If you feel that you have arrived to this page by mistake, please continue installation:</p>
41
+ <button class="form-button" type="button" onclick="location.href='<?php echo $this->mageUrl() ?>'"><span>Continue Magento installation</span></button>
42
+ <br/><br/><br/>
43
+ <p>Alternatively, you could proceed with Re-Downloading all packages</p>
44
+ <?php echo($this->get('channel_notice')); ?>
45
+ <form id="reinstall_all" method="post" action="<?php echo $this->url('connectInstallAll') ?>&force=1" target="connect_iframe" onsubmit="return installAll(true)">
46
+ <fieldset class="fieldset-download">
47
+ <?php endif; ?>
48
+
49
+ <table cellspacing="0" class="form-list">
50
+ <tr>
51
+ <td class="label">Magento Connect Channel Protocol:</td>
52
+ <td class="value">
53
+ <select id="protocol" name="protocol">
54
+ <option value="http" <?php if ($this->get('protocol')=='http'):?>selected="selected"<?php endif ?>>Http</option>
55
+ <option value="ftp" <?php if ($this->get('protocol')=='ftp'):?>selected="selected"<?php endif ?>>Ftp</option>
56
+ </select>
57
+ </td>
58
+ </tr>
59
+ <?php echo($this->get('channel_protocol_fields')); ?>
60
+ <tr>
61
+ <td class="label">Use Custom Permissions:</td>
62
+ <td class="value">
63
+ <select onchange="togglePanel(this)" id="use_custom_permissions_mode" name="use_custom_permissions_mode">
64
+ <option value="1" <?php if ($this->get('use_custom_permissions_mode')=='1'):?>selected="selected"<?php endif ?>>Yes</option>
65
+ <option value="0" <?php if ($this->get('use_custom_permissions_mode')=='0'):?>selected="selected"<?php endif ?>>No</option>
66
+ </select>
67
+ </td>
68
+ </tr>
69
+ </table>
70
+ <table cellspacing="0" cellpadding="0" class="form-list" id="use_custom_permissions_mode_panel" <?php if ($this->get('use_custom_permissions_mode')=='0'):?>style="display:none;"<?php endif ?> >
71
+ <tr>
72
+ <td class="label">Folders:</td>
73
+ <td class="value">
74
+ <input id="mkdir_mode" name="mkdir_mode" value="<?php echo($this->get('mkdir_mode'));?>" type="text" class="input-text"></input>
75
+ </td>
76
+ </tr>
77
+ <tr>
78
+ <td class="label">Files:</td>
79
+ <td class="value">
80
+ <input id="chmod_file_mode" name="chmod_file_mode" value="<?php echo($this->get('chmod_file_mode'));?>" type="text" class="input-text"></input>
81
+ </td>
82
+ </tr>
83
+ </table>
84
+ <table cellspacing="0" cellpadding="0" class="form-list">
85
+ <tr>
86
+ <td class="label">Deployment Type:</td>
87
+ <td class="value">
88
+ <select id="inst_protocol" onchange="togglePanel(this)" name="inst_protocol">
89
+ <option value="0">Local Filesystem</option>
90
+ <option value="1">FTP Connection</option>
91
+ </select>
92
+ </td>
93
+ </tr>
94
+ </table>
95
+ <table cellspacing="0" cellpadding="0" class="form-list" id="inst_protocol_panel">
96
+ <tr>
97
+ <td class="label">Host:</td>
98
+ <td class="value">
99
+ <input type="text" class="input-text" id="ftp_host" value="" name="ftp_host" />
100
+ </td>
101
+ </tr>
102
+
103
+ <tr>
104
+ <td class="label">User:</td>
105
+ <td class="value">
106
+ <input type="text" class="input-text" id="ftp_login" value="" name="ftp_login" />
107
+ </td>
108
+ </tr>
109
+
110
+ <tr>
111
+ <td class="label">Password:</td>
112
+ <td class="value">
113
+ <input type="password" id="ftp_password" value="" name="ftp_password" class="input-text" />
114
+ </td>
115
+ </tr>
116
+
117
+ <tr>
118
+ <td class="label">Installation Path:</td>
119
+ <td class="value">
120
+ <input id="ftp_path" name="ftp_path" value="" type="text" class="input-text" />
121
+ </td>
122
+ </tr>
123
+ </table>
124
+
125
+ <?php if (!$this->controller()->isDownloaded()): ?>
126
+ <button class="form-button" type="submit">Start the download process</button>
127
+ </fieldset>
128
+ </form>
129
+ <?php else: ?>
130
+ <button class="form-button" type="submit">Re-Download All Magento Core Packages</button>
131
+ </fieldset>
132
+ </form>
133
+ <?php endif; ?>
134
+
135
+ <br/>
136
+ <?php echo $this->template('connect/iframe.phtml') ?>
137
+
138
+ <a name="connect_iframe_result"></a>
139
+ <div id="connect_iframe_success" style="display:none">
140
+ <?php $this->set('messages', array('success'=>array(
141
+ 'Download completed. You can proceed with installation',
142
+ ))) ?>
143
+ <?php echo $this->template('messages.phtml') ?>
144
+
145
+ <button class="form-button" type="button" onclick="location.href='<?php echo $this->mageUrl() ?>'"><span>Continue Magento installation</span></button>
146
+ </div>
147
+
148
+ <div id="connect_iframe_failure" style="display:none">
149
+ <?php $this->set('messages', array('error'=>array('There was a problem during downloading of Magento packages. Please check the output frame for errors information and refresh the page to retry again.'))) ?>
150
+ <?php echo $this->template('messages.phtml') ?>
151
+ <button class="form-button" type="button" onclick="location.reload()"><span>Refresh</span></button>
152
+ </div>
153
+
154
+ <script type="text/javascript">
155
+ function togglePanel (element)
156
+ {
157
+ if (element.value == '1') {
158
+ disabledMode = '';
159
+ } else {
160
+ disabledMode = 'none';
161
+ }
162
+ document.getElementById(element.id+'_panel').style.display = disabledMode;
163
+ }
164
+ togglePanel(document.getElementById('use_custom_permissions_mode'));
165
+ togglePanel(document.getElementById('inst_protocol'));
166
+ </script>
167
+
168
+ <script type="text/javascript">
169
+ function installAll(force)
170
+ {
171
+ if (force) {
172
+ if (!confirm("This will delete all files from core packages.\n\nAre you sure you wish to force re-install all Magento files?")) {
173
+ return false;
174
+ }
175
+ }
176
+ /**
177
+ * @TODO: create validation of directory/file permission fields
178
+ */
179
+
180
+ return onSubmit();
181
+ }
182
+ </script>
183
+
184
+ <?php echo $this->template('install/footer.phtml') ?>
downloader/template/install/footer.phtml ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <!-- [end] content -->
28
+ </div>
29
+ </div>
30
+
31
+ <!-- [end] center -->
32
+ </div>
33
+ <!-- [end] middle -->
34
+
35
+ <!-- [start] footer -->
36
+ <div class="footer-container">
37
+ <div class="footer">
38
+ <p class="legality">
39
+ Help Us to Keep Magento Healthy - <a href="http://www.magentocommerce.com/bug-tracking" id="bug_tracking_link"><strong>Report All Bugs</strong></a> (Downloader ver. <?php echo Maged_Controller::getVersion();?>)<br/>
40
+
41
+ <script type="text/javascript">
42
+ $('bug_tracking_link').target = "varien_external";
43
+ </script>
44
+ Magento is a trademark of Magento, Inc. Copyright &copy; 2010 Magento Inc.</p>
45
+ </div>
46
+ </div>
47
+ <!-- [end] footer -->
48
+ </body>
49
+ </html>
downloader/template/install/header.phtml ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
28
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
29
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
30
+ <head>
31
+ <title>Magento Installation Wizard</title>
32
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
33
+
34
+ <link type="image/x-icon" href="<?php echo $this->baseUrl()?>/favicon.ico" rel="icon"/>
35
+ <link type="image/x-icon" href="<?php echo $this->baseUrl()?>/favicon.ico" rel="shortcut icon"/>
36
+
37
+ <script type="text/javascript" src="<?php echo $this->baseUrl()?>/js/prototype.js" ></script>
38
+
39
+ <link rel="stylesheet" href="<?php echo $this->baseUrl()?>/skin/install/reset.css" type="text/css" media="all"/>
40
+ <link rel="stylesheet" href="<?php echo $this->baseUrl()?>/skin/install/boxes.css" type="text/css" media="all"/>
41
+ <link rel="stylesheet" href="<?php echo $this->baseUrl()?>/skin/install/clears.css" type="text/css" media="all"/>
42
+
43
+ <!--[if IE]><link rel="stylesheet" href="<?php echo $this->baseUrl()?>/skin/install/iestyles.css" type="text/css" media="all"/><![endif]-->
44
+ <!--[if lt IE 7]><link rel="stylesheet" href="<?php echo $this->baseUrl()?>/skin/install/ie7minus.css" type="text/css" media="all"/><![endif]-->
45
+ </head>
46
+
47
+ <body>
48
+ <!-- [start] header -->
49
+ <div class="header">
50
+ <div class="header-top-container">
51
+ <div class="header-top">
52
+ <h1 id="logo">
53
+ <a href="<?php echo $this->baseUrl()?>"><img src="<?php echo $this->baseUrl()?>/skin/install/images/<?php echo($this->get('channel_logo')); ?>.gif" alt="Magento"/></a>
54
+ </h1>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ <!-- [end] header -->
59
+
60
+ <!-- [start] middle -->
61
+ <div class="middle-container">
62
+ <div class="middle col-2-left-layout">
63
+
64
+
65
+
66
+ <!-- [start] left -->
67
+
68
+ <div class="col-left side-col">
69
+ <div style="border:1px solid #ccc; background:#f6f6f6;">
70
+ <h2 style="margin-bottom:0; border-bottom:1px solid #ccc; padding:4px 10px; color:#3c5974; font-size:1.4em;">Installation</h2>
71
+ <ol style="padding:10px; border-top:1px solid #fff;">
72
+ <li>Welcome</li>
73
+ <li>Validation</li>
74
+ <li>Magento Connect Manager Deployment</li>
75
+ <?php echo($this->get('channel_steps')); ?>
76
+ <li style="color:green; font-weight:bold; ">Download</li>
77
+ <li >License Agreement</li>
78
+ <li >Localization</li>
79
+ <li >Configuration</li>
80
+
81
+ <li >Create Admin Account</li>
82
+ <li >You're All Set!</li>
83
+ </ol>
84
+ </div>
85
+
86
+ <br/>
87
+ <p>
88
+ Having trouble installing Magento? Check out our <a href="http://www.magentocommerce.com/install" id="installation_guide_link">Installation Guide</a>
89
+ <script type="text/javascript">
90
+ $('installation_guide_link').target = "installation_guide";
91
+ </script>
92
+
93
+ </p>
94
+ &nbsp;
95
+ </div>
96
+ <div id="main" class="col-main">
97
+ <!-- [start] global messages -->
98
+ <!-- [end] global messages -->
99
+ <!-- [start] content -->
downloader/template/install/writable.phtml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php echo $this->template('install/header.phtml') ?>
28
+ <div class="page-head">
29
+ <h3 style="color:red">Error: Please check for sufficient write file permissions</h3>
30
+ </div>
31
+
32
+ <p>Your Magento folder does not have sufficient write permissions, which this web based downloader requires.</p>
33
+ <p>If you wish to proceed downloading Magento packages online, please set all Magento folders to have writable permission for the web server user (example: apache) and press the "Refresh" button to try again.</p>
34
+
35
+ <button class="form-button" type="button" onclick="location.reload()"><span>Refresh</span></button>
36
+ <br/><br/><br/>
37
+ <p>To learn more about setting write permissions, please visit <a href="http://www.magentocommerce.com/knowledge-base/entry/magento-installation-guide" target="Install_Help">the Magento community site</a> for further details.</p>
38
+ <p>Alternatively, if you are a developer and familiar with SVN, you can follow <a href="http://www.magentocommerce.com/svn" target="Install_Help">these instructions</a> to check out the latest Magento branch.</p>
39
+ <?php echo $this->template('install/footer.phtml') ?>
40
+
downloader/template/login.phtml ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php echo $this->template('header.phtml') ?>
28
+ <?php if ($returnUrl = $this->controller()->session()->getReturnUrl()): ?>
29
+ <a class="f-right" href="<?php echo htmlentities($returnUrl) ?>">Return to Magento Administration</a>
30
+ <?php endif ?>
31
+ <div style="width:300px; padding:20px; margin:90px auto !important; background:#f6f6f6;">
32
+ <form method="post" action="#">
33
+ <h2 class="page-head">Log In</h2>
34
+ <p><small>Please re-enter your Magento Adminstration Credentials.<br/>Only administrators with full permissions will be able to log in.</small></p>
35
+ <table class="form-list">
36
+ <tr><td class="label"><label for="username">Username:</label></td><td class="value"><input id="username" name="username" value=""/></td></tr>
37
+ <tr><td class="label"><label for="password">Password:</label></td><td class="value"><input type="password" id="password" name="password"/></td></tr>
38
+ <tr><td></td>
39
+ <td class="value"><button type="submit">Log In</button></td></tr>
40
+ </table>
41
+ </form>
42
+ </div>
43
+ <?php echo $this->template('footer.phtml') ?>
downloader/template/messages.phtml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php if ($messages = $this->get('messages')): ?>
28
+ <ul class="msgs">
29
+ <?php foreach ($messages as $type=>$msgs): ?>
30
+ <li>
31
+ <ul class="<?php echo $type ?>-msg">
32
+ <?php foreach ($msgs as $msg): ?>
33
+ <li><?php echo $msg ?></li>
34
+ <?php endforeach; ?>
35
+ </ul>
36
+ </li>
37
+ <?php endforeach; ?>
38
+ </ul>
39
+ <?php endif; ?>
downloader/template/noroute.phtml ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php echo $this->template('header.phtml') ?>
28
+ <h2 class="page-head">404 - Invalid Page</h2>
29
+ <p>Vestibulum tristique venenatis velit. Ut urna nisl, dignissim vitae, cursus eget, pulvinar scelerisque, lectus. In ac leo id libero consequat dignissim. Sed aliquam est a pede. Phasellus ut turpis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed magna leo, volutpat eget, pretium tristique, varius vitae, tellus. Sed odio ante, sagittis id, euismod eu, bibendum quis, purus. Proin consectetuer elementum nunc. Mauris turpis.</p>
30
+ <?php echo $this->template('footer.phtml') ?>
31
+
downloader/template/settings.phtml ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php echo $this->template('header.phtml') ?>
28
+
29
+ <script type="text/javascript">
30
+ function useCustomPermissions (element)
31
+ {
32
+ if (element.value == '1') {
33
+ disabledMode = 'block';
34
+ } else {
35
+ disabledMode = 'none';
36
+ }
37
+ document.getElementById('use_custom_permissions_mode_panel').style.display = disabledMode;
38
+ }
39
+ function changeDeploymentType (element)
40
+ {
41
+ if (element.value == 'ftp') {
42
+ disabledMode = 'block';
43
+ } else {
44
+ disabledMode = 'none';
45
+ }
46
+ document.getElementById('deployment_type_panel').style.display = disabledMode;
47
+ }
48
+ </script>
49
+
50
+ <div class="settings-page">
51
+ <h2 class="page-head">Settings</h2>
52
+ <form action="<?php echo $this->url('settingsPost') ?>" method="post">
53
+ <fieldset>
54
+ <p>Magento Extensions are available in three different versions.</p>
55
+ <ul class="disc">
56
+ <li><strong>Stable</strong> means the extension can be used in a production environment.</li>
57
+ <li><strong>Beta</strong> means the extension is not recommended for use in a production environment.</li>
58
+ <li><strong>Alpha</strong> means the extension is still in development.</li>
59
+ </ul>
60
+ <p><strong>Please note: extensions are provided as is. Make sure to backup your data before installing new extensions.</strong></p>
61
+ <table cellspacing="0" class="form-list">
62
+ <tr>
63
+ <td class="label">Magento Connect Channel Protocol:</td>
64
+ <td class="value">
65
+ <select id="protocol" name="protocol">
66
+ <option value="http" <?php if ($this->get('protocol')=='http'):?>selected="selected"<?php endif ?>>Http</option>
67
+ <option value="ftp" <?php if ($this->get('protocol')=='ftp'):?>selected="selected"<?php endif ?>>Ftp</option>
68
+ </select>
69
+ </td>
70
+ </tr>
71
+ <?php echo $this->get('channel_protocol_fields'); ?>
72
+ <tr>
73
+ <td class="label">Preferred State:</td>
74
+ <td class="value">
75
+ <select id="preferred_state" name="preferred_state">
76
+ <option value="stable" <?php if ($this->get('preferred_state')=='stable'):?>selected="selected"<?php endif ?>>Stable</option>
77
+ <option value="beta" <?php if ($this->get('preferred_state')=='beta'):?>selected="selected"<?php endif ?>>Beta</option>
78
+ <option value="alpha" <?php if ($this->get('preferred_state')=='alpha'):?>selected="selected"<?php endif ?>>Alpha</option>
79
+ </select>
80
+ </td>
81
+ </tr>
82
+ <!--
83
+ <tr>
84
+ <td class="label">Magento Installation Directory:</td>
85
+ <td class="value"><input name="mage_dir" value="<?php echo htmlentities($this->get('mage_dir'))?>" style="width:250px;"/></td>
86
+ </tr>
87
+ -->
88
+ </table>
89
+ <p><strong>Permission to create new files and folders.</strong></p>
90
+ <table cellspacing="0" class="form-list">
91
+ <tr>
92
+ <td class="label">Use custom permissions:</td>
93
+ <td class="value">
94
+ <select onchange="useCustomPermissions(this)" id="use_custom_permissions_mode" name="use_custom_permissions_mode">
95
+ <option value="1" <?php if ($this->get('use_custom_permissions_mode')=='1'):?>selected="selected"<?php endif ?>>Yes</option>
96
+ <option value="0" <?php if ($this->get('use_custom_permissions_mode')=='0'):?>selected="selected"<?php endif ?>>No</option>
97
+ </select>
98
+ </td>
99
+ </tr>
100
+ </table>
101
+ <table cellspacing="0" class="form-list" id="use_custom_permissions_mode_panel" <?php if ($this->get('use_custom_permissions_mode')=='0'):?>style="display:none;"<?php endif ?>>
102
+ <tr>
103
+ <td class="label">Folders:</td>
104
+ <td class="value">
105
+ <input id="mkdir_mode" name="mkdir_mode" value="<?php echo($this->get('mkdir_mode'));?>" class="input-text" type="text"></input>
106
+ </td>
107
+ </tr>
108
+ <tr>
109
+ <td class="label">Files:</td>
110
+ <td class="value">
111
+ <input id="chmod_file_mode" name="chmod_file_mode" value="<?php echo($this->get('chmod_file_mode'));?>" class="input-text" type="text"></input>
112
+ </td>
113
+ </tr>
114
+ </table>
115
+
116
+ <p><strong>Deployment.</strong></p>
117
+ <table cellspacing="0" class="form-list">
118
+ <tr>
119
+ <td class="label">Deployment Type:</td>
120
+ <td class="value">
121
+ <input value="fs" type="radio" name="deployment_type" id="deployment_fs" onclick="changeDeploymentType(this)" <?php if ($this->get('deployment_type')=='fs'):?>checked="checked"<?php endif ?> <?php if ($this->get('fs_disabled')):?>disabled="disabled"<?php endif ?> />
122
+ <label for="deployment_fs"> <span class="label">Local Filesystem</span> </label>
123
+ </td>
124
+ </tr>
125
+ <tr>
126
+ <td class="label">&nbsp;</td>
127
+ <td class="value">
128
+ <input value="ftp" type="radio" name="deployment_type" id="deployment_ftp" onclick="changeDeploymentType(this)" <?php if ($this->get('deployment_type')=='ftp'):?>checked="checked"<?php endif ?> />
129
+ <label for="deployment_ftp"><span class="label">FTP Connection</span></label>
130
+ </td>
131
+ </tr>
132
+ </table>
133
+ <table cellspacing="0" class="form-list" id="deployment_type_panel" <?php if ($this->get('deployment_type')!='ftp'):?>style="display:none;"<?php endif ?>>
134
+ <tr>
135
+ <td class="label">FTP Host:</td>
136
+ <td class="value">
137
+ <input id="ftp_host" name="ftp_host" value="<?php echo($this->get('ftp_host'));?>" class="input-text" type="text"></input>
138
+ </td>
139
+ </tr>
140
+ <tr>
141
+ <td class="label">FTP Login:</td>
142
+ <td class="value">
143
+ <input id="ftp_login" name="ftp_login" value="<?php echo($this->get('ftp_login'));?>" class="input-text" type="text"></input>
144
+ </td>
145
+ </tr>
146
+ <tr>
147
+ <td class="label">FTP Password:</td>
148
+ <td class="value">
149
+ <input id="ftp_password" name="ftp_password" value="<?php echo($this->get('ftp_password'));?>" class="input-text" type="password"></input>
150
+ </td>
151
+ </tr>
152
+ <tr>
153
+ <td class="label">Installation Path:</td>
154
+ <td class="value">
155
+ <input id="ftp_path" name="ftp_path" value="<?php echo($this->get('ftp_path'));?>" class="input-text" type="text"></input>
156
+ </td>
157
+ </tr>
158
+ </table>
159
+
160
+ <p><button type="submit">Save Settings</button></p>
161
+ </fieldset>
162
+ </form>
163
+ </div>
164
+
165
+ <?php echo $this->template('footer.phtml') ?>
166
+
downloader/template/writable.phtml ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <div class="error-msg">
28
+ <h4>Warning: Your Magento folder does not have sufficient write permissions.</h4>
29
+ </div>
30
+
31
+ <p>
32
+ If you wish to proceed downloading Magento packages online, please set all Magento folders to
33
+ have writable permission for the web server user (example: apache) or set up FTP Connection on the
34
+ Magento Connect Manager <a href="<?php echo $this->url('settings')?>">Settings</a> tab.
35
+ </p>
index.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage
23
+ * @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ if (version_compare(phpversion(), '5.2.0', '<')===true) {
28
+ echo '<div style="font:12px/1.35em arial, helvetica, sans-serif;"><div style="margin:0 0 25px 0; border-bottom:1px solid #ccc;"><h3 style="margin:0; font-size:1.7em; font-weight:normal; text-transform:none; text-align:left; color:#2f2f2f;">Whoops, it looks like you have an invalid PHP version.</h3></div><p>Magento supports PHP 5.2.0 or newer. <a href="http://www.magentocommerce.com/install" target="">Find out</a> how to install</a> Magento using PHP-CGI as a work-around.</p></div>';
29
+ exit;
30
+ }
31
+
32
+ /**
33
+ * Error reporting
34
+ */
35
+ error_reporting(E_ALL | E_STRICT);
36
+
37
+ /**
38
+ * Compilation includes configuration file
39
+ */
40
+ $compilerConfig = 'includes/config.php';
41
+ if (file_exists($compilerConfig)) {
42
+ include $compilerConfig;
43
+ }
44
+
45
+ $mageFilename = 'app/Mage.php';
46
+ $maintenanceFile = 'maintenance.flag';
47
+
48
+ if (!file_exists($mageFilename)) {
49
+ if (is_dir('downloader')) {
50
+ header("Location: downloader");
51
+ } else {
52
+ echo $mageFilename." was not found";
53
+ }
54
+ exit;
55
+ }
56
+
57
+ if (file_exists($maintenanceFile)) {
58
+ include_once dirname(__FILE__) . '/errors/503.php';
59
+ exit;
60
+ }
61
+
62
+ require_once $mageFilename;
63
+
64
+ #Varien_Profiler::enable();
65
+
66
+ if (isset($_SERVER['MAGE_IS_DEVELOPER_MODE'])) {
67
+ Mage::setIsDeveloperMode(true);
68
+ }
69
+
70
+ #ini_set('display_errors', 1);
71
+
72
+ umask(0);
73
+
74
+ /* Store or website code */
75
+ $mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : '';
76
+
77
+ /* Run store or run website */
78
+ $mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store';
79
+
80
+ Mage::run($mageRunCode, $mageRunType);
mage ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+
3
+ # REPLACE with your PHP5 binary path (example: /usr/local/php5/bin/php )
4
+ #MAGE_PHP_BIN="php"
5
+
6
+ MAGE_PHP_SCRIPT="mage.php"
7
+ DOWNLOADER_PATH='downloader'
8
+
9
+ # initial setup
10
+ if test "x$1" = "xmage-setup"; then
11
+ echo 'Running initial setup...'
12
+
13
+ if test "x$2" != "x"; then
14
+ MAGE_ROOT_DIR="$2"
15
+ else
16
+ MAGE_ROOT_DIR="`pwd`"
17
+ fi
18
+
19
+ $0 config-set magento_root "$MAGE_ROOT_DIR"
20
+ $0 config-set preferred_state beta
21
+ $0 channel-add http://connect20.magentocommerce.com/community
22
+ exit
23
+ fi
24
+
25
+ # check that mage pear was initialized
26
+
27
+ if test "x$1" != "xconfig-set" &&
28
+ test "x$1" != "xconfig-get" &&
29
+ test "x$1" != "xconfig-show" &&
30
+ test "x$1" != "xchannel-add" &&
31
+ test "x`$0 config-get magento_root`" = "x"; then
32
+ echo 'Please initialize Magento Connect installer by running:'
33
+ echo "$0 mage-setup"
34
+ exit;
35
+ fi
36
+
37
+ # find which PHP binary to use
38
+ if test "x$MAGE_PHP_BIN" != "x"; then
39
+ PHP="$MAGE_PHP_BIN"
40
+ else
41
+ PHP=php
42
+ fi
43
+
44
+
45
+ # get default pear dir of not set
46
+ if test "x$MAGE_ROOT_DIR" = "x"; then
47
+ MAGE_ROOT_DIR="`pwd`/$DOWNLOADER_PATH"
48
+ fi
49
+
50
+ exec $PHP -C -q $INCARG -d output_buffering=1 -d variables_order=EGPCS \
51
+ -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" \
52
+ -d auto_prepend_file="" -d auto_append_file="" \
53
+ $MAGE_ROOT_DIR/$MAGE_PHP_SCRIPT "$@"
54
+
package.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Mage_Downloader</name>
4
+ <version>1.6.1.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Magento Downloader</summary>
10
+ <description>Magento Downloader</description>
11
+ <notes>1.6.1.0</notes>
12
+ <authors><author><name>Magento Core Team</name><user>core</user><email>core@magentocommerce.com</email></author></authors>
13
+ <date>2011-10-19</date>
14
+ <time>11:50:15</time>
15
+ <contents><target name="mage"><dir name="downloader"><dir name="js"><file name="prototype.js" hash="3766aeff5778b54f74f93670322ca0df"/></dir><dir name="Maged"><dir name="Connect"><file name="Frontend.php" hash="e469328440d5d865db40ed6dec2eb0dd"/></dir><file name="Connect.php" hash="3878355516c34d9544a02d44a4c1e2b8"/><file name="Controller.php" hash="667cee056eef10004144cbadab05a299"/><file name="Exception.php" hash="31befe07df0a61598f063f543991a04b"/><dir name="Model"><dir name="Config"><file name="Abstract.php" hash="b87bd9947efce3f373ff65e0c997334e"/><file name="Community.php" hash="0e39f2375ec50ef5c8d7994e67eaf49e"/><file name="Interface.php" hash="fe6daef73f9f63adcce14dd322a41050"/></dir><file name="Config.php" hash="0fdf21421b2874620f4708b835ad34d5"/><dir name="Connect"><file name="Request.php" hash="9b89d6528986fcd5b97d59a8ceb48eac"/></dir><file name="Connect.php" hash="c63a751c9c720a3c8b670134b816c2aa"/><file name="Dowloader.php" hash="01885097ba694f6e0119f3eaecfa463f"/><file name="Session.php" hash="2876ecde6b2c2bba65e11c3dcf2d913f"/></dir><file name="Model.php" hash="9d43f384a202246af906c65e156d4aaa"/><file name="View.php" hash="38f23f08650249dcb75ff6a0e203ad28"/></dir><dir name="skin"><file name="boxes.css" hash="5a6a94b06fbd4335b4d0f78b94cb9712"/><file name="ie7boxes.css" hash="c9e684ca787f6521190922e7e2e6ed9e"/><file name="ieboxes.css" hash="ff95c4f8ade70c9178f1315eb61eaabe"/><dir name="images"><file name="Magento_Connect.jpg" hash="20e1378c09506fdc5723abc0115d5f57"/><file name="ajax-loader-tr.gif" hash="1ae32bc8232ff2527c627e5b38eb319a"/><file name="btn_bg.gif" hash="37c51a4d48a92da9648dcd3ca011039f"/><file name="header_bg.gif" hash="8440b04c5cb6b1451bb886bfbef260a5"/><file name="logo.gif" hash="5eb089ecea67d82311d7c91898460104"/><file name="nav_bg.gif" hash="1cb1366f03a9efad6b17e4483aef20cf"/><file name="nav_separator.gif" hash="492011a7de2de84a9c7837bfd879ab95"/></dir><dir name="install"><file name="boxes.css" hash="b6d074b3fce501813ed1d8dd323bf422"/><file name="clears.css" hash="bc94c9e4ee77d82530ca33b468b502e4"/><file name="ie7minus.css" hash="e0bad17242a3b6c20516bb292bf16493"/><file name="iestyles.css" hash="eb20094050695e0e02f0318b37c24e08"/><dir name="images"><file name="error_msg_icon.gif" hash="e4f28607f075a105e53fa3113d84bd26"/><file name="footer_bg.gif" hash="d59784af16fd95ea82226e5708a89232"/><file name="footer_container_bg.gif" hash="d468e3943943cbbf711586e69d40ca42"/><file name="footer_info_separator.gif" hash="7da64eefaf4da3855ab6ee76dbced0c2"/><file name="footer_informational_bg.gif" hash="72d37f4b2ea747bf8969c2654ad1d1e0"/><file name="footer_left.gif" hash="2b15a54bea9409a75c142d14a62f0149"/><file name="footer_legality_bg.gif" hash="4eb1602e3369dccd901ffe98ea0fd4b3"/><file name="footer_right.gif" hash="a45eaf35c8797d299bd4d9b936528e8f"/><file name="header_bg.gif" hash="795c6de754d0d49717ed08d5cd8168c8"/><file name="header_nav_bg.gif" hash="80c6a18686eb0243e06d6176506a2502"/><file name="header_top_bg.jpg" hash="143f524392ee62fcc8183f5930d7258b"/><file name="header_top_container_bg.jpg" hash="294c18f3f6b838bba06ae41dd3c3d638"/><file name="logo.gif" hash="073a947a39b967af678455a5c7f66e90"/><file name="main_bg.gif" hash="cf18ba9f7c7e6b058b439cde1a897e9c"/><file name="main_container_bg.gif" hash="a8f5717873dc6cf8f6bd22924b5838fe"/><file name="note_msg_icon.gif" hash="e774ee481a2820789c1a77112377c4e0"/><file name="success_msg_icon.gif" hash="834dfafd5f8b44c4b24a4c00add56fcf"/><file name="validation_advice_bg.gif" hash="b85432906de8985a8b14eeb2dc652d3c"/></dir><file name="reset.css" hash="f473723e7a0aff5d6feedbbab6cb3392"/></dir></dir><dir name="template"><dir name="connect"><file name="iframe.phtml" hash="2aa7c28d092c43e14b8b1fe413e6a126"/><file name="packages.phtml" hash="72c6024a9891c01b603f2766f52ff914"/><file name="packages_prepare.phtml" hash="bd34d2a794e5fcc84d4ea22b5754d250"/></dir><file name="exception.phtml" hash="ce8145052f0a730088fc849c04c58c64"/><file name="footer.phtml" hash="454299883c093cc98b4550c99bba03b9"/><file name="header.phtml" hash="73ab5e15a8a58d624fb5b8e48da679d3"/><file name="index.phtml" hash="1c7d5cbca5c16632db3f891024086947"/><dir name="install"><file name="download.phtml" hash="b7f283992b89cae9e85cc655e4b2d4e3"/><file name="footer.phtml" hash="6a70fd31200cb9bfddf65d7f8f67ac5e"/><file name="header.phtml" hash="f07d63df229468c28043869f0b71e194"/><file name="writable.phtml" hash="2815049a02b3f1110b9f22e22047b941"/></dir><file name="login.phtml" hash="ad91f8daa2d8a8974782350a2d2e2578"/><file name="messages.phtml" hash="8753c0c5599fa55a190c4913651b2c77"/><file name="noroute.phtml" hash="ad5ded291fcbf3899af4f499b77aaf42"/><file name="settings.phtml" hash="5bda5f6e749e288f7e2cb0fc2b7f1b83"/><file name="writable.phtml" hash="5fc31df4f9795e8febe39da1e59d91cd"/><file name=".htaccess" hash="72617d60821288133a367f70bf39ad93"/></dir><file name="index.php" hash="db1b840cef501ba7830d1035d6a3df7b"/><dir name="lib"><dir name="Mage"><dir name="Archive"><file name="Abstract.php" hash="a17be2772775eac2d1e3a36041a9f3c1"/><file name="Bz.php" hash="4e95c019f7c8983ecb225d0847806bed"/><file name="Gz.php" hash="e832e68bd2a3165234b6d6b52b3fcac0"/><file name="Interface.php" hash="1c57bd8e6ee7dbe4cfcaa3dfdceb1d7b"/><file name="Tar.php" hash="12983e34995349ab736eb8c5bbe03ba6"/></dir><file name="Archive.php" hash="7947ccf15f5df8300e7cf1a4681b9569"/><dir name="Autoload"><file name="Simple.php" hash="e062bd1b45f0b08ac456d3e0dc4c06b6"/></dir><dir name="Connect"><dir name="Channel"><file name="Generator.php" hash="4bbda17b29549ae9a50ea09c0db54649"/><file name="Parser.php" hash="3546e3b66eafe78bdd5628dc37f4bca9"/><file name="VO.php" hash="0525a71b043486aca9febcac6ce0ccff"/></dir><dir name="Command"><file name="Channels.php" hash="83e47fe8f407212ecc1797028211d15d"/><file name="Channels_Header.php" hash="8a828b219ec1b57eba88806845f133cb"/><file name="Config.php" hash="22161cf90d8d2abb5409a30dbe28a44c"/><file name="Config_Header.php" hash="0ce12f7207fe610f886aae15df145615"/><file name="Install.php" hash="b40177f31744db26010c8fbe8e10b05a"/><file name="Install_Header.php" hash="1d4da6660edb2e63ea9a223ccfe4610d"/><file name="Package.php" hash="09d265ec9666b7729276a54c88db1263"/><file name="Package_Header.php" hash="102080d8fad7234b60b103a5dbf65754"/><file name="Registry.php" hash="898b91578ee622b4914023edc9e34984"/><file name="Registry_Header.php" hash="fb37813d34f75835e4ecccea704b2ab0"/><file name="Remote.php" hash="3b0f8aa676ddd677e3a57823d8b0c60e"/><file name="Remote_Header.php" hash="9bd703a45c70ccc959f922392decc962"/></dir><file name="Command.php" hash="b3314fecd974fc3d767049cf323cc254"/><file name="Config.php" hash="4d688d01fd05522fa36166656bd5c697"/><file name="Converter.php" hash="435aad5d121240eb7784f3f71a848392"/><dir name="Frontend"><file name="CLI.php" hash="0b71bae7609966ebfcfc04f63a0318a3"/></dir><file name="Frontend.php" hash="811d665cee46fdbea623d651cf4ac44b"/><file name="Ftp.php" hash="4adbc5b56bf2be7ca7d042f78ae61298"/><dir name="Loader"><file name="Ftp.php" hash="1fbff02e85c5e2f7f0e61d8577c248d6"/></dir><file name="Loader.php" hash="ba5151383e4931a7f767a2d1897cb2a7"/><dir name="Package"><file name="Extension.php" hash="68b329da9893e34099c7d8ad5cb9c940"/><file name="Hotfix.php" hash="370177a5cf2f3397e0b341466d34de75"/><file name="Maintainer.php" hash="68b329da9893e34099c7d8ad5cb9c940"/><file name="Reader.php" hash="7fa1d41c6145f178e50e8a266e361f1e"/><file name="Target.php" hash="09c91f931b37f5e350a7ebdbb6bbf442"/><file name="VO.php" hash="e42f4d13abcaa766ca35f24c6280043b"/><file name="Writer.php" hash="32088dd140dfd14b3bde9c11a32b7d35"/></dir><file name="Package.php" hash="bcc3ed40ad75f37e6be0d90e833a84bb"/><file name="Packager.php" hash="812c9dd97f990744d4a763e4b6c3a7b5"/><dir name="Repository"><file name="Abstract.php" hash="68b329da9893e34099c7d8ad5cb9c940"/><dir name="Channel"><file name="Abstract.php" hash="68b329da9893e34099c7d8ad5cb9c940"/><file name="Commercial.php" hash="68b329da9893e34099c7d8ad5cb9c940"/><file name="Community.php" hash="68b329da9893e34099c7d8ad5cb9c940"/><file name="Core.php" hash="68b329da9893e34099c7d8ad5cb9c940"/></dir><file name="Channel.php" hash="68b329da9893e34099c7d8ad5cb9c940"/><file name="Local.php" hash="68b329da9893e34099c7d8ad5cb9c940"/></dir><file name="Repository.php" hash="68b329da9893e34099c7d8ad5cb9c940"/><file name="Rest.php" hash="9bf931f43e0840f903ce9089d90779a2"/><file name="Singleconfig.php" hash="bdcb3dcfb2a58b290cce8da370f8ac9c"/><dir name="Structures"><file name="Graph.php" hash="bb484f7ed43d819d9964c3dfa0489641"/><file name="Node.php" hash="5fe101c2a3c371ebca23b1a77a4d8b9a"/></dir><file name="Validator.php" hash="500f1fec82dc873ef02fae0d738b5162"/></dir><dir name="DB"><file name="Exception.php" hash="38385d6b8ba6dfabf53aa275ca5b1086"/><file name="Mysqli.php" hash="7afa22548284f2e6e8796fce50f736ce"/></dir><file name="Exception.php" hash="a5e649c88e376f850b83d35900525a7f"/><dir name="HTTP"><dir name="Client"><file name="Curl.php" hash="8eba20650fc9da09d8585e31ea3bd053"/><file name="Socket.php" hash="a1b2788a4fa596f70430d309ffc8f59f"/></dir><file name="Client.php" hash="189e5288453ce792e1eacbb178e20fd1"/><file name="IClient.php" hash="eb44927eabc6a87fbf37d52643732b2d"/></dir><dir name="System"><file name="Args.php" hash="a3058a52f975e8436a8d2b113943489a"/><file name="Dirs.php" hash="0addfeb8f206cc67539ca0625921e016"/></dir><dir name="Xml"><file name="Generator.php" hash="c0b790125cc714d1ca43cfdc046768ed"/><file name="Parser.php" hash="6f8ac6fb3c6332c257d28e335909e855"/></dir></dir></dir><file name="config.ini" hash="a52ba98e71ab19de387b3af1a04c6102"/><file name=".htaccess" hash="520cc012c84739584526b8a9ff098e23"/><file name="mage.php" hash="6de4d106e8080bd2be838d1674bf6136"/></dir><dir name="."><file name=".htaccess" hash="8c1f49780253bb13b4fa89d604e814b6"/><file name="index.php" hash="20b1633bd332a08e643afa4590ab8564"/><file name="mage" hash="091c45355c62a9189cff45c09328037c"/></dir></target></contents>
16
+ <compatible/>
17
+ <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
18
+ </package>