*/ if(!defined('DOKU_INC')) die(); require_once(DOKU_PLUGIN."indexmenu/inc/pclzip.lib.php"); if(!defined('INDEXMENU_IMG_ABSDIR')) define('INDEXMENU_IMG_ABSDIR', DOKU_PLUGIN."indexmenu/images"); define('INDEXMENU_ICOS', 'base,folder,folderopen,folderh,folderhopen,page,plus,minus,nolines_plus,nolines_minus,minusbottom,plusbottom,join,joinbottom,line,empty'); class admin_plugin_indexmenu extends DokuWiki_Admin_Plugin { var $req = 'fetch'; var $repos = array( "url" => array(DOKU_URL), "status" => array(""), ); var $selected = -1; /** * return sort order for position in admin menu */ function getMenuSort() { return 999; } /** * handle user request */ function handle() { $url = "http://samuele.netsons.org/dokuwiki"; if(empty($url)) { $this->repos['url'][] = $this->getLang('no_repos'); $this->repos['status'][] = "disabled"; $this->repos['install'][] = -1; } else { $this->repos['url'] = array_merge($this->repos['url'], explode(',', $url)); } if(!isset($_REQUEST['req'])) return; // first time - nothing to do $this->req = $_REQUEST['req']; if(is_numeric($_REQUEST['repo'])) $this->selected = $_REQUEST['repo']; } /** * output appropriate html */ function html() { global $conf; ptln('
'); ptln('

'.$this->getLang('menu').'

'); ptln($this->_donate()); ptln('
'); ptln(' '.$this->getLang('checkupdates').''); $this->_form_open("checkupdates"); $this->_form_close('check'); if($this->req == 'checkupdates') { $this->_checkupdates(); } ptln('
'); ptln('
'); ptln(' Themes'); ptln(' '); ptln(' '); $n = 0; //cycles thru repositories urls foreach($this->repos['url'] as $url) { ptln(' '); ptln(' '); //list requested theme if($n == $this->selected) { ptln(' '); } $n++; } ptln('
'); ptln(' '.$this->getLang('infos').''); ptln('
'); $legend = ($n == 0) ? $conf['title'] : $this->repos['url'][$n]; ptln(' '); ptln(' '); $this->_form_open("fetch", $n); $this->_form_close("fetch"); ptln('
'); if($this->req == 'install') $this->install($this->selected, $_REQUEST['name']); if($this->req == 'upload' && $_REQUEST['name']) { $info = ""; if(isset($_REQUEST['author_info'])) { $obfuscate = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] '); $info .= "author=".strtr($_REQUEST['author_info'], $obfuscate)."\n"; } if(isset($_REQUEST['url_info'])) $info .= "url=".$_REQUEST['url_info']."\n"; if(isset($_REQUEST['author_info'])) $info .= "description=".$_REQUEST['author_info']; if(!$this->upload($_REQUEST['name'], $info)) msg($this->getLang('install_no'), -1); } if($this->req == 'delete' && $_REQUEST['name']) $this->_delete($_REQUEST['name']); ptln('
'); $this->dolist($n); ptln('
'); ptln('
'); ptln('
'); } /** * Connect to theme repository and list themes * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Samuele Tognini */ function dolist($n) { global $INFO; if($n === false) return; //info.txt keys to parse $keys = array('author', 'url', 'description'); $icos = explode(',', INDEXMENU_ICOS); $turl = ""; $info = ""; //get list $data = $this->_remotequery($this->repos['url'][$n]."/lib/plugins/indexmenu/ajax.php?req=local"); $data = explode(",", $data); //print themes for($i = 3; $i < count($data); $i++) { $theme = $data[$i]; $turl = $data[1].$data[2]."/".$theme; ptln(' '.$theme.''); ptln('
'); ptln('
'); //print images foreach(array_slice($icos, 0, 8) as $ico) { $ext = explode(".", $theme); $ext = array_pop($ext); $ext = ($ext == $theme) ? '.gif' : ".$ext"; ptln(' '.$ico.''); } ptln('
'); //get theme info.txt if($info = $this->_remotequery($turl."/info.txt", false)) { foreach($keys as $key) { if(!preg_match('/'.$key.'=(.*)/', $info, $out)) continue; ptln("
"); ptln(" ".hsc($key).": ".hsc($out[1])); ptln("
"); } } if($n == 0) { $act = "upload"; if($theme != "default") { $this->_form_open("delete", $n); ptln(' '); $this->_form_close("delete"); } } else { $act = "install"; ptln(' Download'); } $this->_form_open($act, $n); if($n == 0 && !is_file(INDEXMENU_IMG_ABSDIR."/".$theme."/info.txt")) { ptln('
author:").'" size="50" maxlength="100" />
'); ptln(' url:
'); ptln(' description:
'); } ptln(' '); $this->_form_close($act); ptln('

'); } } /** * Download and install themes * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Samuele Tognini */ function install($n, $name) { $repo = $this->repos['url'][$n]; if(!isset($name)) return false; $return = true; if(!$absdir = $this->checktmpsubdir()) return false; $tmp = $absdir."/tmp"; //send theme list request if(!$zipfile = io_download($repo."/lib/plugins/indexmenu/ajax.php?req=send&t=".$name, "$tmp/", true)) { msg($this->getLang('down_err').": $name", -1); $return = false; } else { //create zip $zip = new PclZip("$tmp/$zipfile"); $regexp = "/^".$name."\/(info.txt)|(style.css)|(".str_replace(",", "|", INDEXMENU_ICOS).")\.(gif|png|jpg)$/i"; $status = $zip->extract(PCLZIP_OPT_PATH, $absdir."/", PCLZIP_OPT_BY_PREG, $regexp); //error if($status == 0) { msg($this->getLang('zip_err')." $tmp/$zipfile: ".$zip->errorName(true), -1); $return = false; } else { msg("$name ".$this->getLang('install_ok'), 1); } } //clean tmp $this->_rm_dir($tmp); return $return; } /** * Remove a directory * */ function _rm_dir($path) { if(!is_string($path) || $path == "") return false; if(is_dir($path)) { if(!$dh = @opendir($path)) return false; while($f = readdir($dh)) { if($f == '..' || $f == '.') continue; $this->_rm_dir("$path/$f"); } closedir($dh); return @rmdir($path); } else { return @unlink($path); } } /** * Retrive and create themes tmp directory * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Samuele Tognini */ function checktmpsubdir() { $tmp = INDEXMENU_IMG_ABSDIR."/tmp"; if(!io_mkdir_p($tmp)) { msg($this->getLang('dir_err').": $tmp", -1); return false; } return INDEXMENU_IMG_ABSDIR; } /** * Upload a theme into my site * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Samuele Tognini */ function upload($theme, $info) { $return = true; $host = 'samuele.netsons.org'; $path = '/dokuwiki/lib/plugins/indexmenu/upload/index.php'; //TODO: merge zip creation with that in ajax.php (create a class?) if(!$absdir = $this->checktmpsubdir()) return false; $tmp = $absdir."/tmp"; $zipfile = "$theme.zip"; $filelist = "$absdir/$theme"; //create info if(!empty($info)) { io_savefile("$tmp/$theme/info.txt", $info); $filelist .= ",$tmp/$theme"; } //create zip $zip = new PclZip("$tmp/$zipfile"); $status = $zip->create($filelist, PCLZIP_OPT_REMOVE_ALL_PATH); if($status == 0) { //error msg($this->getLang('zip_err').": ".$zip->errorName(true), -1); $return = false; } else { //prepare POST headers. $boundary = "---------------------------".uniqid(""); $data = join("", file("$tmp/$zipfile")); $header = "POST $path HTTP/1.0\r\n"; $header .= "Host: $host\r\n"; $header .= "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061024 Iceweasel/2.0 (Debian-2.0+dfsg-1)\r\n"; $header .= "Content-type: multipart/form-data, boundary=$boundary\r\n"; $body = "--".$boundary."\r\n"; $body .= "Content-Disposition: form-data; name=\"userfile\"; filename=\"$zipfile\"\r\n"; $body .= "Content-Type: application/x-zip-compressed\r\n\r\n"; $body .= $data."\r\n"; $body .= "--".$boundary."\r\n"; $body .= "Content-Disposition: form-data; name=\"upload\"\r\n\r\n"; $body .= "Upload\r\n"; $body .= "--".$boundary."--\r\n"; $header .= "Content-Length: ".strlen($body)."\r\n\r\n"; //connect and send zip if($fp = fsockopen($host, 80)) { fwrite($fp, $header.$body); //reply $buf = ""; while(!feof($fp)) { $buf .= fgets($fp, 3200); } fclose($fp); //parse resply if(preg_match("/(.*)/s", $buf, $match)) { $str = substr($match[1], 4, 7); switch($str) { case "ERROR ": $mesg_type = -1; break; case "SUCCESS": $mesg_type = 1; break; default: $mesg_type = 2; } msg($match[1], $mesg_type); } else { $return = false; } } else { $return = false; } } $this->_rm_dir($tmp); return $return; } /** * Check for new messages from upstream * * @author Samuele Tognini */ function _checkupdates() { require_once (DOKU_INC.'inc/HTTPClient.php'); global $conf; global $INFO; $w = -1; $date = $this->getInfo('date'); $date = $date['date']; $data = $this->_remotequery("http://samuele.netsons.org/dokuwiki/lib/plugins/indexmenu/remote.php?check=$date"); if($data === "") { msg($this->getLang('noupdates'), 1); $data .= @preg_replace('/\n\n.*$/s', '', @io_readFile(DOKU_PLUGIN.'indexmenu/changelog'))."\n%\n"; $w = 1; } else { $data = preg_replace('/\/i', "", $data); $data = preg_replace('/\t/', " ", $data); } $data = preg_replace('/\[\[(?!(http|https))(.:)(.*?)\]\]/s', "[[plugin:$3]]", $data); $data = preg_replace('/\[\[(?!(http|https))(.*?)\]\]/s', "[[http://www.dokuwiki.org/$2]]", $data); $msgs = explode("\n%\n", $data); foreach($msgs as $msg) { if($msg) { $msg = p_render('xhtml', p_get_instructions($msg), $info); msg($msg, $w); } } } /** * Get url response and check it * * @author Samuele Tognini */ function _remotequery($url, $tag = true) { require_once (DOKU_INC.'inc/HTTPClient.php'); $http = new DokuHTTPClient(); $http->timeout = 8; $data = $http->get($url); if($tag) { if($data === false) { msg($this->getLang('conn_err'), -1); } else { (substr($data, 0, 9) === "indexmenu") ? $data = substr($data, 9) : $data = ""; } } return $data; } /** * Open an html form * * @author Samuele Tognini */ function _form_open($act, $n = -1) { global $ID; ptln('
'); ptln(' '); ptln(' '); ptln(' '); ptln(' '); } /** * Close the html form * * @author Samuele Tognini */ function _form_close($act) { ptln(' repos['status'][$n].' value="'.$this->getLang($act).'" />'); ptln(' '); } /** * Remove an installed theme * * @author Samuele Tognini */ function _delete($theme) { if($theme == "default") return; if($this->_rm_dir(INDEXMENU_IMG_ABSDIR."/".utf8_encodeFN(basename($theme)))) { msg($this->getLang('delete_ok').": $theme.", 1); } else { msg($this->getLang('delete_no').": $theme.", -1); } } /** * Print the donate button. * * @author Samuele Tognini */ function _donate() { $out = "
\n"; $out .= '

'.$this->getLang('donation_text').'

'; $out .= '
'."\n"; $out .= ''."\n"; $out .= ''."\n"; $out .= ''."\n"; $out .= ''."\n"; $out .= "
\n"; return $out; } }