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