dokuwiki-indexmenu-plugin – Blame information for rev 3
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | <?php |
2 | /** |
||
3 | * Indexmenu Admin Plugin: Indexmenu Component. |
||
4 | * |
||
5 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) |
||
6 | * @author Samuele Tognini <samuele@samuele.netsons.org> |
||
7 | */ |
||
8 | |||
9 | if(!defined('DOKU_INC')) die(); |
||
10 | |||
11 | require_once(DOKU_PLUGIN."indexmenu/inc/pclzip.lib.php"); |
||
12 | |||
13 | if(!defined('INDEXMENU_IMG_ABSDIR')) define('INDEXMENU_IMG_ABSDIR', DOKU_PLUGIN."indexmenu/images"); |
||
14 | define('INDEXMENU_ICOS', 'base,folder,folderopen,folderh,folderhopen,page,plus,minus,nolines_plus,nolines_minus,minusbottom,plusbottom,join,joinbottom,line,empty'); |
||
15 | |||
16 | class admin_plugin_indexmenu extends DokuWiki_Admin_Plugin { |
||
17 | var $req = 'fetch'; |
||
18 | var $repos = array( |
||
19 | "url" => array(DOKU_URL), |
||
20 | "status" => array(""), |
||
21 | ); |
||
22 | |||
23 | var $selected = -1; |
||
24 | |||
25 | /** |
||
26 | * return sort order for position in admin menu |
||
27 | */ |
||
28 | function getMenuSort() { |
||
29 | return 999; |
||
30 | } |
||
31 | |||
32 | /** |
||
33 | * handle user request |
||
34 | */ |
||
35 | function handle() { |
||
36 | $url = "http://samuele.netsons.org/dokuwiki"; |
||
37 | if(empty($url)) { |
||
38 | $this->repos['url'][] = $this->getLang('no_repos'); |
||
39 | $this->repos['status'][] = "disabled"; |
||
40 | $this->repos['install'][] = -1; |
||
41 | } else { |
||
42 | $this->repos['url'] = array_merge($this->repos['url'], explode(',', $url)); |
||
43 | } |
||
44 | |||
45 | if(!isset($_REQUEST['req'])) return; // first time - nothing to do |
||
46 | $this->req = $_REQUEST['req']; |
||
47 | |||
48 | if(is_numeric($_REQUEST['repo'])) $this->selected = $_REQUEST['repo']; |
||
49 | } |
||
50 | |||
51 | /** |
||
52 | * output appropriate html |
||
53 | */ |
||
54 | function html() { |
||
55 | global $conf; |
||
56 | ptln('<div id="config__manager">'); |
||
57 | ptln(' <h1>'.$this->getLang('menu').'</h1>'); |
||
58 | ptln($this->_donate()); |
||
59 | ptln(' <fieldset>'); |
||
60 | ptln(' <legend>'.$this->getLang('checkupdates').'</legend>'); |
||
61 | $this->_form_open("checkupdates"); |
||
62 | $this->_form_close('check'); |
||
63 | if($this->req == 'checkupdates') { |
||
64 | $this->_checkupdates(); |
||
65 | } |
||
66 | ptln(' </fieldset>'); |
||
67 | ptln(' <fieldset>'); |
||
68 | ptln(' <legend>Themes</legend>'); |
||
69 | ptln(' <table class="inline">'); |
||
70 | ptln(' <tr class="default"><td class="label" colspan="2">'); |
||
71 | ptln(' <span class="outkey">'.$this->getLang('infos').'</span>'); |
||
72 | ptln(' </td></tr>'); |
||
73 | $n = 0; |
||
74 | //cycles thru repositories urls |
||
75 | foreach($this->repos['url'] as $url) { |
||
76 | ptln(' <tr class="search_hit"><td>'); |
||
77 | $legend = ($n == 0) ? $conf['title'] : $this->repos['url'][$n]; |
||
78 | ptln(' <span><label><strong>'.$legend.'</strong></label></span>'); |
||
79 | ptln(' </td>'); |
||
80 | ptln(' <td class="value">'); |
||
81 | $this->_form_open("fetch", $n); |
||
82 | $this->_form_close("fetch"); |
||
83 | ptln(' </td></tr>'); |
||
84 | //list requested theme |
||
85 | if($n == $this->selected) { |
||
86 | ptln(' <tr class="default"><td colspan="2">'); |
||
87 | if($this->req == 'install') $this->install($this->selected, $_REQUEST['name']); |
||
88 | if($this->req == 'upload' && $_REQUEST['name']) { |
||
89 | $info = ""; |
||
90 | if(isset($_REQUEST['author_info'])) { |
||
91 | $obfuscate = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] '); |
||
92 | $info .= "author=".strtr($_REQUEST['author_info'], $obfuscate)."\n"; |
||
93 | } |
||
94 | if(isset($_REQUEST['url_info'])) $info .= "url=".$_REQUEST['url_info']."\n"; |
||
95 | if(isset($_REQUEST['author_info'])) $info .= "description=".$_REQUEST['author_info']; |
||
96 | if(!$this->upload($_REQUEST['name'], $info)) msg($this->getLang('install_no'), -1); |
||
97 | } |
||
98 | if($this->req == 'delete' && $_REQUEST['name']) $this->_delete($_REQUEST['name']); |
||
99 | ptln(' </td></tr><tr><td colspan="2">'); |
||
100 | $this->dolist($n); |
||
101 | ptln(' </td></tr>'); |
||
102 | } |
||
103 | $n++; |
||
104 | } |
||
105 | ptln(' </table>'); |
||
106 | ptln(' </fieldset>'); |
||
107 | ptln('</div>'); |
||
108 | } |
||
109 | |||
110 | /** |
||
111 | * Connect to theme repository and list themes |
||
112 | * |
||
113 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) |
||
114 | * @author Samuele Tognini <samuele@samuele.netsons.org> |
||
115 | */ |
||
116 | function dolist($n) { |
||
117 | global $INFO; |
||
118 | if($n === false) return; |
||
119 | //info.txt keys to parse |
||
120 | $keys = array('author', 'url', 'description'); |
||
121 | $icos = explode(',', INDEXMENU_ICOS); |
||
122 | $turl = ""; |
||
123 | $info = ""; |
||
124 | //get list |
||
125 | $data = $this->_remotequery($this->repos['url'][$n]."/lib/plugins/indexmenu/ajax.php?req=local"); |
||
126 | $data = explode(",", $data); |
||
127 | //print themes |
||
128 | for($i = 3; $i < count($data); $i++) { |
||
129 | $theme = $data[$i]; |
||
130 | $turl = $data[1].$data[2]."/".$theme; |
||
131 | ptln(' <em>'.$theme.'</em>'); |
||
132 | ptln(' <div class="indexmenu_list_themes">'); |
||
133 | ptln(' <div>'); |
||
134 | //print images |
||
135 | foreach(array_slice($icos, 0, 8) as $ico) { |
||
136 | $ext = explode(".", $theme); |
||
137 | $ext = array_pop($ext); |
||
138 | $ext = ($ext == $theme) ? '.gif' : ".$ext"; |
||
139 | ptln(' <img src="'.$turl."/".$ico.$ext.'" title="'.$ico.'" alt="'.$ico.'" />'); |
||
140 | } |
||
141 | ptln(' </div>'); |
||
142 | //get theme info.txt |
||
143 | if($info = $this->_remotequery($turl."/info.txt", false)) { |
||
144 | foreach($keys as $key) { |
||
145 | if(!preg_match('/'.$key.'=(.*)/', $info, $out)) continue; |
||
146 | ptln(" <div>"); |
||
147 | ptln(" <strong>".hsc($key).": </strong>".hsc($out[1])); |
||
148 | ptln(" </div>"); |
||
149 | } |
||
150 | } |
||
151 | if($n == 0) { |
||
152 | $act = "upload"; |
||
153 | if($theme != "default") { |
||
154 | $this->_form_open("delete", $n); |
||
155 | ptln(' <input type="hidden" name="name" value="'.$theme.'" />'); |
||
156 | $this->_form_close("delete"); |
||
157 | } |
||
158 | } else { |
||
159 | $act = "install"; |
||
160 | ptln(' <a href="'.$this->repos['url'][$n]."/lib/plugins/indexmenu/ajax.php?req=send&t=".$theme.'">Download</a>'); |
||
161 | } |
||
162 | $this->_form_open($act, $n); |
||
163 | if($n == 0 && !is_file(INDEXMENU_IMG_ABSDIR."/".$theme."/info.txt")) { |
||
164 | ptln(' <div><strong>author:</strong><input type="text" name="author_info" value="'.$INFO["userinfo"]["name"].hsc(" <".$INFO["userinfo"]["mail"].">").'" size="50" maxlength="100" /><br />'); |
||
165 | ptln(' <strong>url:</strong><input type="text" name="url_info" value="'.$this->repos['url'][$n].'" size="50" maxlength="200" /><br />'); |
||
166 | ptln(' <strong>description:</strong><input type="text" name="description_info" value="" size="50" maxlength="200" /></div>'); |
||
167 | } |
||
168 | ptln(' <input type="hidden" name="name" value="'.$theme.'" />'); |
||
169 | $this->_form_close($act); |
||
170 | ptln(' <br /><br /></div>'); |
||
171 | } |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * Download and install themes |
||
176 | * |
||
177 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) |
||
178 | * @author Samuele Tognini <samuele@samuele.netsons.org> |
||
179 | */ |
||
180 | function install($n, $name) { |
||
181 | $repo = $this->repos['url'][$n]; |
||
182 | if(!isset($name)) return false; |
||
183 | $return = true; |
||
184 | if(!$absdir = $this->checktmpsubdir()) return false; |
||
185 | $tmp = $absdir."/tmp"; |
||
186 | |||
187 | //send theme list request |
||
188 | if(!$zipfile = io_download($repo."/lib/plugins/indexmenu/ajax.php?req=send&t=".$name, "$tmp/", true)) { |
||
189 | msg($this->getLang('down_err').": $name", -1); |
||
190 | $return = false; |
||
191 | } else { |
||
192 | //create zip |
||
193 | $zip = new PclZip("$tmp/$zipfile"); |
||
194 | $regexp = "/^".$name."\/(info.txt)|(style.css)|(".str_replace(",", "|", INDEXMENU_ICOS).")\.(gif|png|jpg)$/i"; |
||
195 | $status = $zip->extract(PCLZIP_OPT_PATH, $absdir."/", PCLZIP_OPT_BY_PREG, $regexp); |
||
196 | //error |
||
197 | if($status == 0) { |
||
198 | msg($this->getLang('zip_err')." $tmp/$zipfile: ".$zip->errorName(true), -1); |
||
199 | $return = false; |
||
200 | } else { |
||
201 | msg("<strong>$name</strong> ".$this->getLang('install_ok'), 1); |
||
202 | } |
||
203 | } |
||
204 | //clean tmp |
||
205 | $this->_rm_dir($tmp); |
||
206 | return $return; |
||
207 | } |
||
208 | |||
209 | /** |
||
210 | * Remove a directory |
||
211 | * |
||
212 | */ |
||
213 | function _rm_dir($path) { |
||
214 | if(!is_string($path) || $path == "") return false; |
||
215 | |||
216 | if(is_dir($path)) { |
||
217 | if(!$dh = @opendir($path)) return false; |
||
218 | |||
219 | while($f = readdir($dh)) { |
||
220 | if($f == '..' || $f == '.') continue; |
||
221 | $this->_rm_dir("$path/$f"); |
||
222 | } |
||
223 | |||
224 | closedir($dh); |
||
225 | return @rmdir($path); |
||
226 | } else { |
||
227 | return @unlink($path); |
||
228 | } |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * Retrive and create themes tmp directory |
||
233 | * |
||
234 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) |
||
235 | * @author Samuele Tognini <samuele@samuele.netsons.org> |
||
236 | */ |
||
237 | function checktmpsubdir() { |
||
238 | $tmp = INDEXMENU_IMG_ABSDIR."/tmp"; |
||
239 | if(!io_mkdir_p($tmp)) { |
||
240 | msg($this->getLang('dir_err').": $tmp", -1); |
||
241 | return false; |
||
242 | } |
||
243 | return INDEXMENU_IMG_ABSDIR; |
||
244 | } |
||
245 | |||
246 | /** |
||
247 | * Upload a theme into my site |
||
248 | * |
||
249 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) |
||
250 | * @author Samuele Tognini <samuele@samuele.netsons.org> |
||
251 | */ |
||
252 | function upload($theme, $info) { |
||
253 | $return = true; |
||
254 | $host = 'samuele.netsons.org'; |
||
255 | $path = '/dokuwiki/lib/plugins/indexmenu/upload/index.php'; |
||
256 | //TODO: merge zip creation with that in ajax.php (create a class?) |
||
257 | if(!$absdir = $this->checktmpsubdir()) return false; |
||
258 | $tmp = $absdir."/tmp"; |
||
259 | $zipfile = "$theme.zip"; |
||
260 | $filelist = "$absdir/$theme"; |
||
261 | //create info |
||
262 | if(!empty($info)) { |
||
263 | io_savefile("$tmp/$theme/info.txt", $info); |
||
264 | $filelist .= ",$tmp/$theme"; |
||
265 | } |
||
266 | //create zip |
||
267 | $zip = new PclZip("$tmp/$zipfile"); |
||
268 | $status = $zip->create($filelist, PCLZIP_OPT_REMOVE_ALL_PATH); |
||
269 | if($status == 0) { |
||
270 | //error |
||
271 | msg($this->getLang('zip_err').": ".$zip->errorName(true), -1); |
||
272 | $return = false; |
||
273 | } else { |
||
274 | //prepare POST headers. |
||
275 | $boundary = "---------------------------".uniqid(""); |
||
276 | $data = join("", file("$tmp/$zipfile")); |
||
277 | $header = "POST $path HTTP/1.0\r\n"; |
||
278 | $header .= "Host: $host\r\n"; |
||
279 | $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"; |
||
280 | $header .= "Content-type: multipart/form-data, boundary=$boundary\r\n"; |
||
281 | $body = "--".$boundary."\r\n"; |
||
282 | $body .= "Content-Disposition: form-data; name=\"userfile\"; filename=\"$zipfile\"\r\n"; |
||
283 | $body .= "Content-Type: application/x-zip-compressed\r\n\r\n"; |
||
284 | $body .= $data."\r\n"; |
||
285 | $body .= "--".$boundary."\r\n"; |
||
286 | $body .= "Content-Disposition: form-data; name=\"upload\"\r\n\r\n"; |
||
287 | $body .= "Upload\r\n"; |
||
288 | $body .= "--".$boundary."--\r\n"; |
||
289 | $header .= "Content-Length: ".strlen($body)."\r\n\r\n"; |
||
290 | |||
291 | //connect and send zip |
||
292 | if($fp = fsockopen($host, 80)) { |
||
293 | fwrite($fp, $header.$body); |
||
294 | //reply |
||
295 | $buf = ""; |
||
296 | while(!feof($fp)) { |
||
297 | $buf .= fgets($fp, 3200); |
||
298 | } |
||
299 | fclose($fp); |
||
300 | //parse resply |
||
301 | if(preg_match("/<!--indexmenu-->(.*)<!--\/indexmenu-->/s", $buf, $match)) { |
||
302 | $str = substr($match[1], 4, 7); |
||
303 | switch($str) { |
||
304 | case "ERROR ": |
||
305 | $mesg_type = -1; |
||
306 | break; |
||
307 | case "SUCCESS": |
||
308 | $mesg_type = 1; |
||
309 | break; |
||
310 | default: |
||
311 | $mesg_type = 2; |
||
312 | } |
||
313 | msg($match[1], $mesg_type); |
||
314 | } else { |
||
315 | $return = false; |
||
316 | } |
||
317 | } else { |
||
318 | $return = false; |
||
319 | } |
||
320 | } |
||
321 | |||
322 | $this->_rm_dir($tmp); |
||
323 | return $return; |
||
324 | } |
||
325 | |||
326 | /** |
||
327 | * Check for new messages from upstream |
||
328 | * |
||
329 | * @author Samuele Tognini <samuele@samuele.netsons.org> |
||
330 | */ |
||
331 | function _checkupdates() { |
||
332 | require_once (DOKU_INC.'inc/HTTPClient.php'); |
||
333 | global $conf; |
||
334 | global $INFO; |
||
335 | $w = -1; |
||
336 | $date = $this->getInfo('date'); |
||
337 | $date = $date['date']; |
||
338 | $data = $this->_remotequery("http://samuele.netsons.org/dokuwiki/lib/plugins/indexmenu/remote.php?check=$date"); |
||
339 | if($data === "") { |
||
340 | msg($this->getLang('noupdates'), 1); |
||
341 | $data .= @preg_replace('/\n\n.*$/s', '', @io_readFile(DOKU_PLUGIN.'indexmenu/changelog'))."\n%\n"; |
||
342 | $w = 1; |
||
343 | } else { |
||
344 | $data = preg_replace('/\<br(\s*)?\/?\>/i', "", $data); |
||
345 | $data = preg_replace('/\t/', " ", $data); |
||
346 | } |
||
347 | $data = preg_replace('/\[\[(?!(http|https))(.:)(.*?)\]\]/s', "[[plugin:$3]]", $data); |
||
348 | $data = preg_replace('/\[\[(?!(http|https))(.*?)\]\]/s', "[[http://www.dokuwiki.org/$2]]", $data); |
||
349 | $msgs = explode("\n%\n", $data); |
||
350 | foreach($msgs as $msg) { |
||
351 | if($msg) { |
||
352 | $msg = p_render('xhtml', p_get_instructions($msg), $info); |
||
353 | msg($msg, $w); |
||
354 | } |
||
355 | } |
||
356 | } |
||
357 | |||
358 | /** |
||
359 | * Get url response and check it |
||
360 | * |
||
361 | * @author Samuele Tognini <samuele@samuele.netsons.org> |
||
362 | */ |
||
363 | function _remotequery($url, $tag = true) { |
||
364 | require_once (DOKU_INC.'inc/HTTPClient.php'); |
||
365 | $http = new DokuHTTPClient(); |
||
366 | $http->timeout = 8; |
||
367 | $data = $http->get($url); |
||
368 | if($tag) { |
||
369 | if($data === false) { |
||
370 | msg($this->getLang('conn_err'), -1); |
||
371 | } else { |
||
372 | (substr($data, 0, 9) === "indexmenu") ? $data = substr($data, 9) : $data = ""; |
||
373 | } |
||
374 | } |
||
375 | return $data; |
||
376 | } |
||
377 | |||
378 | /** |
||
379 | * Open an html form |
||
380 | * |
||
381 | * @author Samuele Tognini <samuele@samuele.netsons.org> |
||
382 | */ |
||
383 | function _form_open($act, $n = -1) { |
||
384 | global $ID; |
||
385 | ptln(' <form action="'.wl($ID).'" method="post">'); |
||
386 | ptln(' <input type="hidden" name="do" value="admin" />'); |
||
387 | ptln(' <input type="hidden" name="page" value="'.$this->getPluginName().'" />'); |
||
388 | ptln(' <input type="hidden" name="req" value="'.$act.'" />'); |
||
389 | ptln(' <input type="hidden" name="repo" value="'.$n.'" />'); |
||
390 | } |
||
391 | |||
392 | /** |
||
393 | * Close the html form |
||
394 | * |
||
395 | * @author Samuele Tognini <samuele@samuele.netsons.org> |
||
396 | */ |
||
397 | function _form_close($act) { |
||
398 | ptln(' <input type="submit" name="btn" '.$this->repos['status'][$n].' value="'.$this->getLang($act).'" />'); |
||
399 | ptln(' </form>'); |
||
400 | } |
||
401 | |||
402 | /** |
||
403 | * Remove an installed theme |
||
404 | * |
||
405 | * @author Samuele Tognini <samuele@samuele.netsons.org> |
||
406 | */ |
||
407 | function _delete($theme) { |
||
408 | if($theme == "default") return; |
||
409 | if($this->_rm_dir(INDEXMENU_IMG_ABSDIR."/".utf8_encodeFN(basename($theme)))) { |
||
410 | msg($this->getLang('delete_ok').": $theme.", 1); |
||
411 | } else { |
||
412 | msg($this->getLang('delete_no').": $theme.", -1); |
||
413 | } |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * Print the donate button. |
||
418 | * |
||
419 | * @author Samuele Tognini <samuele@samuele.netsons.org> |
||
420 | */ |
||
421 | function _donate() { |
||
422 | $out = "<fieldset>\n"; |
||
423 | $out .= '<p>'.$this->getLang('donation_text').'</p>'; |
||
424 | $out .= '<form action="https://www.paypal.com/cgi-bin/webscr" method="post">'."\n"; |
||
425 | $out .= '<input type="hidden" name="cmd" value="_s-xclick" />'."\n"; |
||
426 | $out .= '<input type="hidden" name="hosted_button_id" value="102873" />'."\n"; |
||
427 | $out .= '<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" name="submit" alt="" />'."\n"; |
||
428 | $out .= '<img alt="" src="https://www.paypal.com/it_IT/i/scr/pixel.gif" width="1" height="1" />'."\n"; |
||
429 | $out .= "</form></fieldset>\n"; |
||
430 | return $out; |
||
431 | } |
||
432 | |||
433 | } |