xref: /dokuwiki/inc/actions.php (revision 680824244fa1719cdf9dae5b8c6e74d748459067)
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    header("Location: ".wl($ID,'',true));
312    exit;
313  }
314
315  //handle logout
316  if($act=='logout'){
317    $lockedby = checklock($ID); //page still locked?
318    if($lockedby == $_SERVER['REMOTE_USER'])
319      unlock($ID); //try to unlock
320
321    // do the logout stuff
322    auth_logoff();
323
324    // rebuild info array
325    $INFO = pageinfo();
326
327    return 'login';
328  }
329
330  return $act;
331}
332
333/**
334 * Handle 'edit', 'preview'
335 *
336 * @author Andreas Gohr <andi@splitbrain.org>
337 */
338function act_edit($act){
339  global $ID;
340  global $INFO;
341
342  //check if locked by anyone - if not lock for my self
343  $lockedby = checklock($ID);
344  if($lockedby) return 'locked';
345
346  lock($ID);
347  return $act;
348}
349
350/**
351 * Handle 'edit', 'preview'
352 *
353 * @author Andreas Gohr <andi@splitbrain.org>
354 */
355function act_export($act){
356  global $ID;
357  global $REV;
358
359  // no renderer for this
360  if($act == 'export_raw'){
361    header('Content-Type: text/plain; charset=utf-8');
362    print rawWiki($ID,$REV);
363    exit;
364  }
365
366  // html export #FIXME what about the template's style?
367  if($act == 'export_xhtml'){
368    global $conf;
369    global $lang;
370    header('Content-Type: text/html; charset=utf-8');
371    ptln('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"');
372    ptln(' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
373    ptln('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'.$conf['lang'].'"');
374    ptln(' lang="'.$conf['lang'].'" dir="'.$lang['direction'].'">');
375    ptln('<head>');
376    ptln('  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />');
377    ptln('  <title>'.$ID.'</title>');
378    tpl_metaheaders();
379    ptln('</head>');
380    ptln('<body>');
381    ptln('<div class="dokuwiki export">');
382    print p_wiki_xhtml($ID,$REV,false);
383    ptln('</div>');
384    ptln('</body>');
385    ptln('</html>');
386    exit;
387  }
388
389  // html body only
390  if($act == 'export_xhtmlbody'){
391    print p_wiki_xhtml($ID,$REV,false);
392    exit;
393  }
394
395  // try to run renderer
396  $mode = substr($act,7);
397  $text = p_cached_output(wikiFN($ID,$REV), $mode);
398  if(!is_null($text)){
399    print $text;
400    exit;
401  }
402
403  return 'show';
404}
405
406/**
407 * Handle 'subscribe', 'unsubscribe'
408 *
409 * @author Steven Danz <steven-danz@kc.rr.com>
410 * @todo   localize
411 */
412function act_subscription($act){
413  global $ID;
414  global $INFO;
415  global $lang;
416
417  $file=metaFN($ID,'.mlist');
418  if ($act=='subscribe' && !$INFO['subscribed']){
419    if ($INFO['userinfo']['mail']){
420      if (io_saveFile($file,$_SERVER['REMOTE_USER']."\n",true)) {
421        $INFO['subscribed'] = true;
422        msg(sprintf($lang[$act.'_success'], $INFO['userinfo']['name'], $ID),1);
423      } else {
424        msg(sprintf($lang[$act.'_error'], $INFO['userinfo']['name'], $ID),1);
425      }
426    } else {
427      msg($lang['subscribe_noaddress']);
428    }
429  } elseif ($act=='unsubscribe' && $INFO['subscribed']){
430    if (io_deleteFromFile($file,$_SERVER['REMOTE_USER']."\n")) {
431      $INFO['subscribed'] = false;
432      msg(sprintf($lang[$act.'_success'], $INFO['userinfo']['name'], $ID),1);
433    } else {
434      msg(sprintf($lang[$act.'_error'], $INFO['userinfo']['name'], $ID),1);
435    }
436  }
437
438  return 'show';
439}
440
441//Setup VIM: ex: et ts=2 enc=utf-8 :
442