1<?php 2/** 3 * eclipseUpdate Plugin 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author i-net software <tools@inetsoftware.de> 7 * @author Gerry Weissbach <gweissbach@inetsoftware.de> 8 */ 9 10// must be run within Dokuwiki 11if(!defined('DOKU_INC')) die(); 12if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 13 14require_once(DOKU_PLUGIN.'syntax.php'); 15 16class syntax_plugin_eclipseupdateurl extends DokuWiki_Syntax_Plugin { 17 18 function getType() { return 'substition'; } 19 function getPType() { return 'block'; } 20 function getSort() { return 99; } 21 22 function connectTo($mode) { 23 $this->Lexer->addSpecialPattern("\[\[eclipseUpdate>.*?\]\]", $mode, 'plugin_eclipseupdateurl'); 24 } 25 26 function handle($match, $state, $pos, Doku_Handler $handler) { 27 28 $ID = substr($match, 16, -2); 29 list( $ID, $opts) = explode( '|', $ID, 2 ); 30 31 $opts = explode( '|', $opts ); 32 $fOpts = array(); 33 $fOpts['amount'] = $this->getConf('showamount'); 34 35 foreach ( $opts as $opt ) { 36 37 if ( empty($opt) ) continue; 38 if ( is_numeric($opt) ) { 39 $fOpts['amount'] = $opt; 40 } else { 41 list($key, $value) = explode('=', $opt, 2); 42 43 switch ( $key ) { 44 case 'direct' : $fOpts['direct'] = true; 45 break; 46 case 'name' : $fOpts['name'] = $value; 47 break; 48 case 'category' : $fOpts['category'] = $value; 49 break; 50 case 'id' : $fOpts['id'] = $value; 51 break; 52 } 53 } 54 } 55 56 57 return array( $ID, $fOpts ); 58 } 59 60 function render($mode, Doku_Renderer $renderer, $data) { 61 62 list ( $data, $opts ) = $data; 63 if ( $mode == 'xhtml' ) { 64 65 if ( !preg_match("/site.xml$/", $data) ) { 66 msg("'$data' is not a valid site.xml for Eclipse Updates"); 67 return false; 68 } 69 70 if ( !preg_match( "&^(?i)https?://&", $data ) ) { 71 $fn = mediaFN($data); 72 if ( !file_exists($fn) ) { 73 msg("'$data' does not exist"); 74 return false; 75 } 76 77 $fn = 'file://' . $fn; 78 } else { 79 $fn = $data; 80 } 81 82 list ($PLUGINDESC, $FEATURELIST) = $this->_getSiteXML($fn); 83 84 if ( $opts['direct'] ) { 85 86 // Selected Category or first 87 $ITEMS = $opts['category'] ? $FEATURELIST[$opts['category']] : array_shift($FEATURELIST); 88 89 // Latest 90 $ITEM = $ITEMS['features'][count($ITEMS['features'])-1]; 91 92 // Plugin Element 93 $PLUGIN = $ITEM['list'][0]; 94 95 if ( $opt['id'] ) { 96 foreach( $ITEM['list'] as $PLUGIN ) { 97 if ( $PLUGIN['id'] != $opt['id'] ) { continue; } 98 break; 99 } 100 } 101 102 // Name 103 $NAME = $opts['name'] ? $opts['name'] : $PLUGIN['id'] . '_' . $PLUGIN['version'] . '.jar'; 104 105 //link 106 $renderer->doc .= $this->tpl_link($ITEM['url'] . 'plugins/' . $PLUGIN['id'] . '_' . $PLUGIN['version'] . '.jar', $NAME); 107 108 return true; 109 } 110 111 $this->_getEclipseList($renderer, $PLUGINSDESC, $FEATURELIST); 112 113 } 114 115 return true; 116 } 117 118 function _getEclipseList(&$renderer, $PLUGINDESC, $FEATURELIST) { 119 120 $renderer->doc .= "<p>$PLUGINDESC</p>"; 121 foreach ( $FEATURELIST as $CATEGORY => $ITEMS ) { 122 123 $renderer->doc .= '<strong>' . $CATEGORY . '</strong>'; 124 125 $renderer->doc .= '<table class="eclipsepluginurl inline">'; 126 127 $renderer->doc .= '<tr>'; 128 $renderer->doc .= '<th>Version</th>'; 129 $renderer->doc .= '<th>Component</th>'; 130 $renderer->doc .= '<th>Size</th>'; 131 $renderer->doc .= '</tr>'; 132 133 foreach ( array_reverse(array_slice($ITEMS['features'], -$opts['amount'])) as $ITEM ) { 134 135 if ( !is_array($ITEM['list']) ) 136 $ITEM['list'] = array($ITEM['list']); 137 138 $renderer->doc .= '<tr>'; 139 $renderer->doc .= '<td rowspan="' . count($ITEM['list']) . '">' . $ITEM['version'] . '</td>'; 140 $renderer->doc .= '<td>'; 141 142 foreach ( $ITEM['list'] as $PLUGIN ) { 143 if ( count($ITEM['list']) > 1 && $PLUGIN != $ITEM['list'][0] ) 144 $renderer->doc .= '</td></tr><tr><td>'; 145 146 $renderer->doc .= $this->tpl_link($ITEM['url'] . 'plugins/' . $PLUGIN['id'] . '_' . $PLUGIN['version'] . '.jar', $PLUGIN['id'] . '_' . $PLUGIN['version'] . '.jar'); 147 148 $renderer->doc .= '</td><td>'; 149 150 $renderer->doc .= sprintf("%.2f MB", ($PLUGIN['download-size'] / 1024)); 151 $renderer->doc .= '</td>'; 152 } 153 154 $renderer->doc .= '</tr>'; 155 } 156 157 $renderer->doc .= '</table>'; 158 } 159 } 160 161 162 function tpl_link($url,$name,$more=''){ 163 164 $return = '<a href="'.$url.'" '; 165 if ($more) $return .= ' '.$more; 166 $return .= ">$name</a>"; 167 return $return; 168 } 169 170 function _getSiteXML($URI) { 171 172 $reader = new XMLReader(); 173 $reader->open($URI); 174 175 $PLUGINURL = null; 176 $PLUGINDESC = null; 177 $PLUGINLIST = array(); 178 179 $FEATURE = null; 180 181 while ($reader->read()) { 182 183 if ( $reader->nodeType !== XMLReader::ELEMENT ) { continue; } 184 185 switch ($reader->name) { 186 187 case 'description': $PLUGINURL = $reader->getAttribute('url'); 188 $PLUGINDESC = $reader->readString(); 189 break; 190 191 case 'feature' : $FEATURE = $this->_getPluginURL($PLUGINURL . $reader->getAttribute('url')); 192 193 if ( $URL === false ) { $FEATURE = null; } 194 195 $FEATURE['id'] = $reader->getAttribute('id'); 196 $FEATURE['version'] = $reader->getAttribute('version'); 197 198 break; 199 200 case 'category' : if ( empty($FEATURE) ) { continue; } 201 $CATEGORY = $reader->getAttribute('name'); 202 203 // Add category 204 if ( empty( $PLUGINLIST[$CATEGORY] ) ) 205 $PLUGINLIST[$CATEGORY] = array ( 206 'label' => null, 207 'features' => array(), 208 ); 209 210 // Put feature and reset 211 $PLUGINLIST[$CATEGORY]['features'][] = $FEATURE; 212 $FEATURE = null; 213 214 break; 215 216 case 'category-def' : $CATEGORY = $reader->getAttribute('name'); 217 $LABEL = $reader->getAttribute('label'); 218 219 if ( !empty( $PLUGINLIST[$CATEGORY] ) ) 220 $PLUGINLIST[$CATEGORY]['label'] = $LABEL; 221 222 break; 223 } 224 } 225 226 return array ($PLUGINDESC, $PLUGINLIST); 227 } 228 229 function _getFeatureXML($STRING) { 230 231 if ( empty($STRING) ) return false; 232 233 $reader = new XMLReader(); 234 $reader->XML($STRING); 235 236 $PLUGINURL = null; 237 $PLUGINDESC = null; 238 $PLUGINLIST = array(); 239 240 while ($reader->read()) { 241 242 if ( $reader->nodeType !== XMLReader::ELEMENT ) { continue; } 243 244 switch ($reader->name) { 245 case 'update' : $PLUGINURL = $reader->getAttribute('url'); 246 $PLUGINDESC = $reader->getAttribute('label'); 247 break; 248 249 case 'plugin' : $PLUGINLIST[] = array ( 250 'id' => $reader->getAttribute('id'), 251 'download-size' => $reader->getAttribute('download-size'), 252 'install-size' => $reader->getAttribute('install-size'), 253 'version' => $reader->getAttribute('version'), 254 ); 255 break; 256 257 default : continue; 258 } 259 } 260 261 return array ( 'url' => $PLUGINURL, 'desc' => $PLUGINDESC, 'list' => $PLUGINLIST); 262 } 263 264 function _getPluginURL($FEATUREURL) { 265 global $conf; 266 267 $CACHE = $conf['cachetime']; 268 $FILE = $this->media_get_from_URL($FEATUREURL,'jar',$CACHE); 269 270 if ( $FILE === false ) { 271 return false; 272 } 273 274 return $this->_getFeatureXML($this->__fileExistsInJar($FILE, 'feature.xml', true)); 275 } 276 277 /** 278 * Download jar files 279 * 280 * @author Andreas Gohr <andi@splitbrain.org> 281 */ 282 function media_get_from_URL($url,$ext,$cache) { 283 global $conf; 284 285 // if no cache or fetchsize just redirect 286 if ($cache==0) return false; 287 if (!$conf['fetchsize']) return false; 288 289 $local = getCacheName(strtolower($url),".media.$ext"); 290 $mtime = @filemtime($local); // 0 if not exists 291 292 //decide if download needed: 293 if( ($mtime == 0) || // cache does not exist 294 ($cache != -1 && $mtime < time()-$cache) // 'recache' and cache has expired 295 ){ 296 if($this->media_download($url,$local)){ 297 return $local; 298 }else{ 299 return false; 300 } 301 } 302 303 //if cache exists use it else 304 if($mtime) return $local; 305 306 //else return false 307 return false; 308 } 309 310 /** 311 * Download image files 312 * 313 * @author Andreas Gohr <andi@splitbrain.org> 314 */ 315 function media_download($url,$file){ 316 global $conf; 317 318 //print $url; 319 320 $http = new DokuHTTPClient(); 321 $http->max_bodysize = $conf['fetchsize']; 322 $http->timeout = 25; //max. 25 sec 323 324 $data = $http->get($url); 325 if(!$data) return false; 326 327 $fileexists = @file_exists($file); 328 $fp = @fopen($file,"w"); 329 if(!$fp) return false; 330 fwrite($fp,$data); 331 fclose($fp); 332 if(!$fileexists and $conf['fperm']) chmod($file, $conf['fperm']); 333 334 // check if it is really a zip 335 $info = @getimagesize($file); 336 if(!$this->__fileExistsInJar($file, 'feature.xml')){ 337 @unlink($file); 338 return false; 339 } 340 341 return true; 342 } 343 344 function __fileExistsInJar($JAR, $NAME, $GET = false) { 345 346 if ( empty( $JAR ) ) return; 347 348 $zip = new ZipArchive; 349 $code = $zip->open($JAR); 350 if ($code === TRUE && !($zip->statName($NAME) === FALSE)) { 351 352 return $GET ? $zip->getFromName($NAME) : TRUE; 353 } 354 355 return false; 356 } 357} 358// vim:ts=4:sw=4:et:enc=utf-8: 359