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