1<?php 2/** 3 * DokuWiki Actions 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8 9 if(!defined('DOKU_INC')) define('DOKU_INC',fullpath(dirname(__FILE__).'/../').'/'); 10 require_once(DOKU_INC.'inc/template.php'); 11 12 13/** 14 * Call the needed action handlers 15 * 16 * @author Andreas Gohr <andi@splitbrain.org> 17 * @triggers ACTION_ACT_PREPROCESS 18 * @triggers ACTION_HEADERS_SEND 19 */ 20function act_dispatch(){ 21 global $INFO; 22 global $ACT; 23 global $ID; 24 global $QUERY; 25 global $lang; 26 global $conf; 27 28 // give plugins an opportunity to process the action 29 $evt = new Doku_Event('ACTION_ACT_PREPROCESS',$ACT); 30 if ($evt->advise_before()) { 31 32 //sanitize $ACT 33 $ACT = act_clean($ACT); 34 35 //check if searchword was given - else just show 36 $s = cleanID($QUERY); 37 if($ACT == 'search' && empty($s)){ 38 $ACT = 'show'; 39 } 40 41 //login stuff 42 if(in_array($ACT,array('login','logout'))){ 43 $ACT = act_auth($ACT); 44 } 45 46 //check if user is asking to (un)subscribe a page 47 if($ACT == 'subscribe' || $ACT == 'unsubscribe') 48 $ACT = act_subscription($ACT); 49 50 //check permissions 51 $ACT = act_permcheck($ACT); 52 53 //register 54 $nil = array(); 55 if($ACT == 'register' && $_POST['save'] && register()){ 56 $ACT = 'login'; 57 } 58 59 if ($ACT == 'resendpwd' && act_resendpwd()) { 60 $ACT = 'login'; 61 } 62 63 //update user profile 64 if (($ACT == 'profile') && updateprofile()) { 65 msg($lang['profchanged'],1); 66 $ACT = 'show'; 67 } 68 69 //save 70 if($ACT == 'save'){ 71 if(checkSecurityToken()){ 72 $ACT = act_save($ACT); 73 }else{ 74 $ACT = 'show'; 75 } 76 } 77 78 //cancel conflicting edit 79 if($ACT == 'cancel') 80 $ACT = 'show'; 81 82 //draft deletion 83 if($ACT == 'draftdel') 84 $ACT = act_draftdel($ACT); 85 86 //draft saving on preview 87 if($ACT == 'preview') 88 $ACT = act_draftsave($ACT); 89 90 //edit 91 if(($ACT == 'edit' || $ACT == 'preview') && $INFO['editable']){ 92 $ACT = act_edit($ACT); 93 }else{ 94 unlock($ID); //try to unlock 95 } 96 97 //handle export 98 if(substr($ACT,0,7) == 'export_') 99 $ACT = act_export($ACT); 100 101 //display some infos 102 if($ACT == 'check'){ 103 check(); 104 $ACT = 'show'; 105 } 106 107 //handle admin tasks 108 if($ACT == 'admin'){ 109 // retrieve admin plugin name from $_REQUEST['page'] 110 if (!empty($_REQUEST['page'])) { 111 $pluginlist = plugin_list('admin'); 112 if (in_array($_REQUEST['page'], $pluginlist)) { 113 // attempt to load the plugin 114 if ($plugin =& plugin_load('admin',$_REQUEST['page']) !== NULL) 115 $plugin->handle(); 116 } 117 } 118 } 119 120 // check permissions again - the action may have changed 121 $ACT = act_permcheck($ACT); 122 } // end event ACTION_ACT_PREPROCESS default action 123 $evt->advise_after(); 124 unset($evt); 125 126 127 //call template FIXME: all needed vars available? 128 $headers[] = 'Content-Type: text/html; charset=utf-8'; 129 trigger_event('ACTION_HEADERS_SEND',$headers,'act_sendheaders'); 130 131 include(template('main.php')); 132 // output for the commands is now handled in inc/templates.php 133 // in function tpl_content() 134} 135 136function act_sendheaders($headers) { 137 foreach ($headers as $hdr) header($hdr); 138} 139 140/** 141 * Sanitize the action command 142 * 143 * Add all allowed commands here. 144 * 145 * @author Andreas Gohr <andi@splitbrain.org> 146 */ 147function act_clean($act){ 148 global $lang; 149 global $conf; 150 151 // check if the action was given as array key 152 if(is_array($act)){ 153 list($act) = array_keys($act); 154 } 155 156 //remove all bad chars 157 $act = strtolower($act); 158 $act = preg_replace('/[^1-9a-z_]+/','',$act); 159 160 if($act == 'export_html') $act = 'export_xhtml'; 161 if($act == 'export_htmlbody') $act = 'export_xhtmlbody'; 162 163 // check if action is disabled 164 if(!actionOK($act)){ 165 msg('Command disabled: '.htmlspecialchars($act),-1); 166 return 'show'; 167 } 168 169 //disable all acl related commands if ACL is disabled 170 if(!$conf['useacl'] && in_array($act,array('login','logout','register','admin', 171 'subscribe','unsubscribe','profile', 172 'resendpwd',))){ 173 msg('Command unavailable: '.htmlspecialchars($act),-1); 174 return 'show'; 175 } 176 177 if(!in_array($act,array('login','logout','register','save','cancel','edit','draft', 178 'preview','search','show','check','index','revisions', 179 'diff','recent','backlink','admin','subscribe', 180 'unsubscribe','profile','resendpwd','recover','wordblock', 181 'draftdel',)) && substr($act,0,7) != 'export_' ) { 182 msg('Command unknown: '.htmlspecialchars($act),-1); 183 return 'show'; 184 } 185 return $act; 186} 187 188/** 189 * Run permissionchecks 190 * 191 * @author Andreas Gohr <andi@splitbrain.org> 192 */ 193function act_permcheck($act){ 194 global $INFO; 195 global $conf; 196 197 if(in_array($act,array('save','preview','edit','recover'))){ 198 if($INFO['exists']){ 199 if($act == 'edit'){ 200 //the edit function will check again and do a source show 201 //when no AUTH_EDIT available 202 $permneed = AUTH_READ; 203 }else{ 204 $permneed = AUTH_EDIT; 205 } 206 }else{ 207 $permneed = AUTH_CREATE; 208 } 209 }elseif(in_array($act,array('login','search','recent','profile'))){ 210 $permneed = AUTH_NONE; 211 }elseif($act == 'register'){ 212 $permneed = AUTH_NONE; 213 }elseif($act == 'resendpwd'){ 214 $permneed = AUTH_NONE; 215 }elseif($act == 'admin'){ 216 if($INFO['ismanager']){ 217 // if the manager has the needed permissions for a certain admin 218 // action is checked later 219 $permneed = AUTH_READ; 220 }else{ 221 $permneed = AUTH_ADMIN; 222 } 223 }else{ 224 $permneed = AUTH_READ; 225 } 226 if($INFO['perm'] >= $permneed) return $act; 227 228 return 'denied'; 229} 230 231/** 232 * Handle 'draftdel' 233 * 234 * Deletes the draft for the current page and user 235 */ 236function act_draftdel($act){ 237 global $INFO; 238 @unlink($INFO['draft']); 239 $INFO['draft'] = null; 240 return 'show'; 241} 242 243/** 244 * Saves a draft on preview 245 * 246 * @todo this currently duplicates code from ajax.php :-/ 247 */ 248function act_draftsave($act){ 249 global $INFO; 250 global $ID; 251 global $conf; 252 if($conf['usedraft'] && $_POST['wikitext']){ 253 $draft = array('id' => $ID, 254 'prefix' => $_POST['prefix'], 255 'text' => $_POST['wikitext'], 256 'suffix' => $_POST['suffix'], 257 'date' => $_POST['date'], 258 'client' => $INFO['client'], 259 ); 260 $cname = getCacheName($draft['client'].$ID,'.draft'); 261 if(io_saveFile($cname,serialize($draft))){ 262 $INFO['draft'] = $cname; 263 } 264 } 265 return $act; 266} 267 268/** 269 * Handle 'save' 270 * 271 * Checks for spam and conflicts and saves the page. 272 * Does a redirect to show the page afterwards or 273 * returns a new action. 274 * 275 * @author Andreas Gohr <andi@splitbrain.org> 276 */ 277function act_save($act){ 278 global $ID; 279 global $DATE; 280 global $PRE; 281 global $TEXT; 282 global $SUF; 283 global $SUM; 284 285 //spam check 286 if(checkwordblock()) 287 return 'wordblock'; 288 //conflict check //FIXME use INFO 289 if($DATE != 0 && @filemtime(wikiFN($ID)) > $DATE ) 290 return 'conflict'; 291 292 //save it 293 saveWikiText($ID,con($PRE,$TEXT,$SUF,1),$SUM,$_REQUEST['minor']); //use pretty mode for con 294 //unlock it 295 unlock($ID); 296 297 //delete draft 298 act_draftdel($act); 299 300 //show it 301 session_write_close(); 302 header("Location: ".wl($ID,'',true)); 303 exit(); 304} 305 306/** 307 * Handle 'login', 'logout' 308 * 309 * @author Andreas Gohr <andi@splitbrain.org> 310 */ 311function act_auth($act){ 312 global $ID; 313 global $INFO; 314 315 //already logged in? 316 if($_SERVER['REMOTE_USER'] && $act=='login'){ 317 header("Location: ".wl($ID,'',true)); 318 exit; 319 } 320 321 //handle logout 322 if($act=='logout'){ 323 $lockedby = checklock($ID); //page still locked? 324 if($lockedby == $_SERVER['REMOTE_USER']) 325 unlock($ID); //try to unlock 326 327 // do the logout stuff 328 auth_logoff(); 329 330 // rebuild info array 331 $INFO = pageinfo(); 332 333 return 'login'; 334 } 335 336 return $act; 337} 338 339/** 340 * Handle 'edit', 'preview' 341 * 342 * @author Andreas Gohr <andi@splitbrain.org> 343 */ 344function act_edit($act){ 345 global $ID; 346 global $INFO; 347 348 //check if locked by anyone - if not lock for my self 349 $lockedby = checklock($ID); 350 if($lockedby) return 'locked'; 351 352 lock($ID); 353 return $act; 354} 355 356/** 357 * Handle 'edit', 'preview' 358 * 359 * @author Andreas Gohr <andi@splitbrain.org> 360 */ 361function act_export($act){ 362 global $ID; 363 global $REV; 364 365 // search engines: never cache exported docs! (Google only currently) 366 header('X-Robots-Tag: noindex'); 367 368 // no renderer for this 369 if($act == 'export_raw'){ 370 header('Content-Type: text/plain; charset=utf-8'); 371 print rawWiki($ID,$REV); 372 exit; 373 } 374 375 // html export #FIXME what about the template's style? 376 if($act == 'export_xhtml'){ 377 global $conf; 378 global $lang; 379 header('Content-Type: text/html; charset=utf-8'); 380 ptln('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'); 381 ptln(' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'); 382 ptln('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'.$conf['lang'].'"'); 383 ptln(' lang="'.$conf['lang'].'" dir="'.$lang['direction'].'">'); 384 ptln('<head>'); 385 ptln(' <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />'); 386 ptln(' <title>'.$ID.'</title>'); 387 tpl_metaheaders(); 388 ptln('</head>'); 389 ptln('<body>'); 390 ptln('<div class="dokuwiki export">'); 391 print p_wiki_xhtml($ID,$REV,false); 392 ptln('</div>'); 393 ptln('</body>'); 394 ptln('</html>'); 395 exit; 396 } 397 398 // html body only 399 if($act == 'export_xhtmlbody'){ 400 print p_wiki_xhtml($ID,$REV,false); 401 exit; 402 } 403 404 // try to run renderer 405 $mode = substr($act,7); 406 $text = p_cached_output(wikiFN($ID,$REV), $mode); 407 $headers = p_get_metadata($ID,"format $mode"); 408 if(!is_null($text)){ 409 if(is_array($headers)) foreach($headers as $key => $val){ 410 header("$key: $val"); 411 } 412 print $text; 413 exit; 414 } 415 416 return 'show'; 417} 418 419/** 420 * Handle 'subscribe', 'unsubscribe' 421 * 422 * @author Steven Danz <steven-danz@kc.rr.com> 423 * @todo localize 424 */ 425function act_subscription($act){ 426 global $ID; 427 global $INFO; 428 global $lang; 429 430 $file=metaFN($ID,'.mlist'); 431 if ($act=='subscribe' && !$INFO['subscribed']){ 432 if ($INFO['userinfo']['mail']){ 433 if (io_saveFile($file,$_SERVER['REMOTE_USER']."\n",true)) { 434 $INFO['subscribed'] = true; 435 msg(sprintf($lang[$act.'_success'], $INFO['userinfo']['name'], $ID),1); 436 } else { 437 msg(sprintf($lang[$act.'_error'], $INFO['userinfo']['name'], $ID),1); 438 } 439 } else { 440 msg($lang['subscribe_noaddress']); 441 } 442 } elseif ($act=='unsubscribe' && $INFO['subscribed']){ 443 if (io_deleteFromFile($file,$_SERVER['REMOTE_USER']."\n")) { 444 $INFO['subscribed'] = false; 445 msg(sprintf($lang[$act.'_success'], $INFO['userinfo']['name'], $ID),1); 446 } else { 447 msg(sprintf($lang[$act.'_error'], $INFO['userinfo']['name'], $ID),1); 448 } 449 } 450 451 return 'show'; 452} 453 454//Setup VIM: ex: et ts=2 enc=utf-8 : 455