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