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