5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author Andreas Gohr <andi@splitbrain.org>
9 if(!defined('DOKU_INC')) die('meh.');
10 require_once(DOKU_INC
.'inc/template.php');
14 * Call the needed action handlers
16 * @author Andreas Gohr <andi@splitbrain.org>
17 * @triggers ACTION_ACT_PREPROCESS
18 * @triggers ACTION_HEADERS_SEND
20 function act_dispatch(){
31 // give plugins an opportunity to process the action
32 $evt = new Doku_Event('ACTION_ACT_PREPROCESS',$ACT);
33 if ($evt->advise_before()) {
36 $ACT = act_clean($ACT);
38 //check if searchword was given - else just show
40 if($ACT == 'search' && empty($s)){
45 if(in_array($ACT,array('login','logout'))){
46 $ACT = act_auth($ACT);
49 //check if user is asking to (un)subscribe a page
50 if($ACT == 'subscribe') {
52 $ACT = act_subscription($ACT);
53 } catch (Exception
$e) {
54 msg($e->getMessage(), -1);
59 $ACT = act_permcheck($ACT);
63 if($ACT == 'register' && $_POST['save'] && register()){
67 if ($ACT == 'resendpwd' && act_resendpwd()) {
72 if ($ACT == 'profile') {
73 if(!$_SERVER['REMOTE_USER']) {
77 msg($lang['profchanged'],1);
85 if(checkSecurityToken()){
86 $ACT = act_revert($ACT);
94 if(checkSecurityToken()){
95 $ACT = act_save($ACT);
101 //cancel conflicting edit
106 if($ACT == 'draftdel')
107 $ACT = act_draftdel($ACT);
109 //draft saving on preview
110 if($ACT == 'preview')
111 $ACT = act_draftsave($ACT);
114 if(($ACT == 'edit' ||
$ACT == 'preview') && $INFO['editable']){
115 $ACT = act_edit($ACT);
117 unlock($ID); //try to unlock
121 if(substr($ACT,0,7) == 'export_')
122 $ACT = act_export($ACT);
132 // retrieve admin plugin name from $_REQUEST['page']
133 if (!empty($_REQUEST['page'])) {
134 $pluginlist = plugin_list('admin');
135 if (in_array($_REQUEST['page'], $pluginlist)) {
136 // attempt to load the plugin
137 if ($plugin =& plugin_load('admin',$_REQUEST['page']) !== null)
143 // check permissions again - the action may have changed
144 $ACT = act_permcheck($ACT);
145 } // end event ACTION_ACT_PREPROCESS default action
146 $evt->advise_after();
149 // when action 'show', the intial not 'show' and POST, do a redirect
150 if($ACT == 'show' && $preact != 'show' && strtolower($_SERVER['REQUEST_METHOD']) == 'post'){
151 act_redirect($ID,$preact);
154 //call template FIXME: all needed vars available?
155 $headers[] = 'Content-Type: text/html; charset=utf-8';
156 trigger_event('ACTION_HEADERS_SEND',$headers,'act_sendheaders');
158 include(template('main.php'));
159 // output for the commands is now handled in inc/templates.php
160 // in function tpl_content()
163 function act_sendheaders($headers) {
164 foreach ($headers as $hdr) header($hdr);
168 * Sanitize the action command
170 * Add all allowed commands here.
172 * @author Andreas Gohr <andi@splitbrain.org>
174 function act_clean($act){
178 // check if the action was given as array key
180 list($act) = array_keys($act);
183 //remove all bad chars
184 $act = strtolower($act);
185 $act = preg_replace('/[^1-9a-z_]+/','',$act);
187 if($act == 'export_html') $act = 'export_xhtml';
188 if($act == 'export_htmlbody') $act = 'export_xhtmlbody';
190 // check if action is disabled
192 msg('Command disabled: '.htmlspecialchars($act),-1);
196 //disable all acl related commands if ACL is disabled
197 if(!$conf['useacl'] && in_array($act,array('login','logout','register','admin',
198 'subscribe','unsubscribe','profile','revert',
199 'resendpwd','subscribens','unsubscribens',))){
200 msg('Command unavailable: '.htmlspecialchars($act),-1);
204 if(!in_array($act,array('login','logout','register','save','cancel','edit','draft',
205 'preview','search','show','check','index','revisions',
206 'diff','recent','backlink','admin','subscribe','revert',
207 'unsubscribe','profile','resendpwd','recover','wordblock',
208 'draftdel','subscribens','unsubscribens',)) && substr($act,0,7) != 'export_' ) {
209 msg('Command unknown: '.htmlspecialchars($act),-1);
216 * Run permissionchecks
218 * @author Andreas Gohr <andi@splitbrain.org>
220 function act_permcheck($act){
224 if(in_array($act,array('save','preview','edit','recover'))){
227 //the edit function will check again and do a source show
228 //when no AUTH_EDIT available
229 $permneed = AUTH_READ
;
231 $permneed = AUTH_EDIT
;
234 $permneed = AUTH_CREATE
;
236 }elseif(in_array($act,array('login','search','recent','profile'))){
237 $permneed = AUTH_NONE
;
238 }elseif($act == 'revert'){
239 $permneed = AUTH_ADMIN
;
240 if($INFO['ismanager']) $permneed = AUTH_EDIT
;
241 }elseif($act == 'register'){
242 $permneed = AUTH_NONE
;
243 }elseif($act == 'resendpwd'){
244 $permneed = AUTH_NONE
;
245 }elseif($act == 'admin'){
246 if($INFO['ismanager']){
247 // if the manager has the needed permissions for a certain admin
248 // action is checked later
249 $permneed = AUTH_READ
;
251 $permneed = AUTH_ADMIN
;
254 $permneed = AUTH_READ
;
256 if($INFO['perm'] >= $permneed) return $act;
264 * Deletes the draft for the current page and user
266 function act_draftdel($act){
268 @unlink
($INFO['draft']);
269 $INFO['draft'] = null;
274 * Saves a draft on preview
276 * @todo this currently duplicates code from ajax.php :-/
278 function act_draftsave($act){
282 if($conf['usedraft'] && $_POST['wikitext']){
283 $draft = array('id' => $ID,
284 'prefix' => $_POST['prefix'],
285 'text' => $_POST['wikitext'],
286 'suffix' => $_POST['suffix'],
287 'date' => $_POST['date'],
288 'client' => $INFO['client'],
290 $cname = getCacheName($draft['client'].$ID,'.draft');
291 if(io_saveFile($cname,serialize($draft))){
292 $INFO['draft'] = $cname;
301 * Checks for spam and conflicts and saves the page.
302 * Does a redirect to show the page afterwards or
303 * returns a new action.
305 * @author Andreas Gohr <andi@splitbrain.org>
307 function act_save($act){
318 //conflict check //FIXME use INFO
319 if($DATE != 0 && @filemtime
(wikiFN($ID)) > $DATE )
323 saveWikiText($ID,con($PRE,$TEXT,$SUF,1),$SUM,$_REQUEST['minor']); //use pretty mode for con
329 session_write_close();
331 // when done, show page
336 * Revert to a certain revision
338 * @author Andreas Gohr <andi@splitbrain.org>
340 function act_revert($act){
345 // when no revision is given, delete current one
346 // FIXME this feature is not exposed in the GUI currently
348 $sum = $lang['deleted'];
350 $text = rawWiki($ID,$REV);
351 if(!$text) return 'show'; //something went wrong
352 $sum = $lang['restored'];
356 if(checkwordblock($Text))
359 saveWikiText($ID,$text,$sum,false);
364 session_write_close();
366 // when done, show current page
367 $_SERVER['REQUEST_METHOD'] = 'post'; //should force a redirect
373 * Do a redirect after receiving post data
375 * Tries to add the section id as hash mark after section editing
377 function act_redirect($id,$preact){
382 //are there any undisplayed messages? keep them in session for display
384 if(isset($MSG) && count($MSG)){
385 //reopen session, store data and close session again
387 $_SESSION[DOKU_COOKIE
]['msg'] = $MSG;
388 session_write_close();
395 //get section name when coming from section edit
396 if($PRE && preg_match('/^\s*==+([^=\n]+)/',$TEXT,$match)){
397 $check = false; //Byref
398 $opts['fragment'] = sectionID($match[0], $check);
401 trigger_event('ACTION_SHOW_REDIRECT',$opts,'act_redirect_execute');
404 function act_redirect_execute($opts){
405 $go = wl($opts['id'],'',true);
406 if(isset($opts['fragment'])) $go .= '#'.$opts['fragment'];
413 * Handle 'login', 'logout'
415 * @author Andreas Gohr <andi@splitbrain.org>
417 function act_auth($act){
422 if(isset($_SERVER['REMOTE_USER']) && $act=='login'){
428 $lockedby = checklock($ID); //page still locked?
429 if($lockedby == $_SERVER['REMOTE_USER'])
430 unlock($ID); //try to unlock
432 // do the logout stuff
435 // rebuild info array
438 act_redirect($ID,'login');
445 * Handle 'edit', 'preview'
447 * @author Andreas Gohr <andi@splitbrain.org>
449 function act_edit($act){
453 //check if locked by anyone - if not lock for my self
454 $lockedby = checklock($ID);
455 if($lockedby) return 'locked';
462 * Export a wiki page for various formats
464 * Triggers ACTION_EXPORT_POSTPROCESS
467 * data['id'] -- page id
468 * data['mode'] -- requested export mode
469 * data['headers'] -- export headers
470 * data['output'] -- export output
472 * @author Andreas Gohr <andi@splitbrain.org>
473 * @author Michael Klier <chi@chimeric.de>
475 function act_export($act){
486 // search engines: never cache exported docs! (Google only currently)
487 $headers['X-Robots-Tag'] = 'noindex';
489 $mode = substr($act,7);
492 $headers['Content-Type'] = 'text/plain; charset=utf-8';
493 $headers['Content-Disposition'] = 'attachment; filename='.noNS($ID).'.txt';
494 $output = rawWiki($ID,$REV);
497 $pre .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' . DOKU_LF
;
498 $pre .= ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . DOKU_LF
;
499 $pre .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'.$conf['lang'].'"' . DOKU_LF
;
500 $pre .= ' lang="'.$conf['lang'].'" dir="'.$lang['direction'].'">' . DOKU_LF
;
501 $pre .= '<head>' . DOKU_LF
;
502 $pre .= ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />' . DOKU_LF
;
503 $pre .= ' <title>'.$ID.'</title>' . DOKU_LF
;
508 $pre .= ob_get_clean();
510 $pre .= '</head>' . DOKU_LF
;
511 $pre .= '<body>' . DOKU_LF
;
512 $pre .= '<div class="dokuwiki export">' . DOKU_LF
;
515 $pre .= tpl_toc(true);
517 $headers['Content-Type'] = 'text/html; charset=utf-8';
518 $output = p_wiki_xhtml($ID,$REV,false);
520 $post .= '</div>' . DOKU_LF
;
521 $post .= '</body>' . DOKU_LF
;
522 $post .= '</html>' . DOKU_LF
;
525 $headers['Content-Type'] = 'text/html; charset=utf-8';
526 $output = p_wiki_xhtml($ID,$REV,false);
529 $output = p_cached_output(wikiFN($ID,$REV), $mode);
530 $headers = p_get_metadata($ID,"format $mode");
534 // prepare event data
537 $data['mode'] = $mode;
538 $data['headers'] = $headers;
539 $data['output'] =& $output;
541 trigger_event('ACTION_EXPORT_POSTPROCESS', $data);
543 if(!empty($data['output'])){
544 if(is_array($data['headers'])) foreach($data['headers'] as $key => $val){
545 header("$key: $val");
547 print $pre.$data['output'].$post;
554 * Handle page 'subscribe'
556 * Throws exception on error.
558 * @author Adrian Lang <lang@cosmocode.de>
560 function act_subscription($act){
565 // get and preprocess data.
567 foreach(array('target', 'style', 'action') as $param) {
568 if (isset($_REQUEST["sub_$param"])) {
569 $params[$param] = $_REQUEST["sub_$param"];
573 // any action given? if not just return and show the subscription page
574 if(!$params['action']) return $act;
576 // Handle POST data, may throw exception.
577 trigger_event('ACTION_HANDLE_SUBSCRIBE', $params, 'subscription_handle_post');
579 $target = $params['target'];
580 $style = $params['style'];
581 $data = $params['data'];
582 $action = $params['action'];
585 require_once DOKU_INC
. 'inc/subscription.php';
586 if (!subscription_set($_SERVER['REMOTE_USER'], $target, $style, $data)) {
587 throw new Exception(sprintf($lang["subscr_{$action}_error"],
588 hsc($INFO['userinfo']['name']),
589 prettyprint_id($target)));
591 msg(sprintf($lang["subscr_{$action}_success"], hsc($INFO['userinfo']['name']),
592 prettyprint_id($target)), 1);
593 act_redirect($ID, $act);
595 // Assure that we have valid data if act_redirect somehow fails.
596 $INFO['subscribed'] = get_info_subscribed();
603 * Validates POST data for a subscribe or unsubscribe request. This is the
604 * default action for the event ACTION_HANDLE_SUBSCRIBE.
606 * @author Adrian Lang <lang@cosmocode.de>
608 function subscription_handle_post(&$params) {
612 // Get and validate parameters.
613 if (!isset($params['target'])) {
614 throw new Exception('no subscription target given');
616 $target = $params['target'];
617 $valid_styles = array('every', 'digest');
618 if (substr($target, -1, 1) === ':') {
619 // Allow “list” subscribe style since the target is a namespace.
620 $valid_styles[] = 'list';
622 $style = valid_input_set('style', $valid_styles, $params,
623 'invalid subscription style given');
624 $action = valid_input_set('action', array('subscribe', 'unsubscribe'),
625 $params, 'invalid subscription action given');
627 // Check other conditions.
628 if ($action === 'subscribe') {
629 if ($INFO['userinfo']['mail'] === '') {
630 throw new Exception($lang['subscr_subscribe_noaddress']);
632 } elseif ($action === 'unsubscribe') {
634 foreach($INFO['subscribed'] as $subscr) {
635 if ($subscr['target'] === $target) {
640 throw new Exception(sprintf($lang['subscr_not_subscribed'],
641 $_SERVER['REMOTE_USER'],
642 prettyprint_id($target)));
644 // subscription_set deletes a subscription if style = null.
648 $data = in_array($style, array('list', 'digest')) ?
time() : null;
649 $params = compact('target', 'style', 'data', 'action');
652 //Setup VIM: ex: et ts=2 enc=utf-8 :