1.9.1
by Clayton Kramer
Integrated Dokuwiki |
1 |
<?php
|
2 |
if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../'); |
|
3 |
||
4 |
// fix when '<?xml' isn't on the very first line
|
|
5 |
if(isset($HTTP_RAW_POST_DATA)) $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA); |
|
6 |
||
7 |
/**
|
|
8 |
* Increased whenever the API is changed
|
|
9 |
*/
|
|
10 |
define('DOKU_XMLRPC_API_VERSION',4); |
|
11 |
||
12 |
require_once(DOKU_INC.'inc/init.php'); |
|
13 |
session_write_close(); //close session |
|
14 |
||
15 |
if(!$conf['xmlrpc']) die('XML-RPC server not enabled.'); |
|
16 |
||
17 |
/**
|
|
18 |
* Contains needed wrapper functions and registers all available
|
|
19 |
* XMLRPC functions.
|
|
20 |
*/
|
|
21 |
class dokuwiki_xmlrpc_server extends IXR_IntrospectionServer { |
|
22 |
var $methods = array(); |
|
23 |
var $public_methods = array(); |
|
24 |
||
25 |
/**
|
|
26 |
* Checks if the current user is allowed to execute non anonymous methods
|
|
27 |
*/
|
|
28 |
function checkAuth(){ |
|
29 |
global $conf; |
|
30 |
global $USERINFO; |
|
31 |
||
32 |
if(!$conf['useacl']) return true; //no ACL - then no checks |
|
33 |
||
34 |
$allowed = explode(',',$conf['xmlrpcuser']); |
|
35 |
$allowed = array_map('trim', $allowed); |
|
36 |
$allowed = array_unique($allowed); |
|
37 |
$allowed = array_filter($allowed); |
|
38 |
||
39 |
if(!count($allowed)) return true; //no restrictions |
|
40 |
||
41 |
$user = $_SERVER['REMOTE_USER']; |
|
42 |
$groups = (array) $USERINFO['grps']; |
|
43 |
||
44 |
if(in_array($user,$allowed)) return true; //user explicitly mentioned |
|
45 |
||
46 |
//check group memberships
|
|
47 |
foreach($groups as $group){ |
|
48 |
if(in_array('@'.$group,$allowed)) return true; |
|
49 |
}
|
|
50 |
||
51 |
//still here? no access!
|
|
52 |
return false; |
|
53 |
}
|
|
54 |
||
55 |
/**
|
|
56 |
* Adds a callback, extends parent method
|
|
57 |
*
|
|
58 |
* add another parameter to define if anonymous access to
|
|
59 |
* this method should be granted.
|
|
60 |
*/
|
|
61 |
function addCallback($method, $callback, $args, $help, $public=false){ |
|
62 |
if($public) $this->public_methods[] = $method; |
|
63 |
return parent::addCallback($method, $callback, $args, $help); |
|
64 |
}
|
|
65 |
||
66 |
/**
|
|
67 |
* Execute a call, extends parent method
|
|
68 |
*
|
|
69 |
* Checks for authentication first
|
|
70 |
*/
|
|
71 |
function call($methodname, $args){ |
|
72 |
if(!in_array($methodname,$this->public_methods) && !$this->checkAuth()){ |
|
73 |
return new IXR_Error(-32603, 'server error. not authorized to call method "'.$methodname.'".'); |
|
74 |
}
|
|
75 |
return parent::call($methodname, $args); |
|
76 |
}
|
|
77 |
||
78 |
/**
|
|
79 |
* Constructor. Register methods and run Server
|
|
80 |
*/
|
|
81 |
function dokuwiki_xmlrpc_server(){ |
|
82 |
$this->IXR_IntrospectionServer(); |
|
83 |
||
84 |
/* DokuWiki's own methods */
|
|
85 |
$this->addCallback( |
|
86 |
'dokuwiki.getXMLRPCAPIVersion', |
|
87 |
'this:getAPIVersion', |
|
88 |
array('integer'), |
|
89 |
'Returns the XMLRPC API version.', |
|
90 |
true
|
|
91 |
);
|
|
92 |
||
93 |
$this->addCallback( |
|
94 |
'dokuwiki.getVersion', |
|
95 |
'getVersion', |
|
96 |
array('string'), |
|
97 |
'Returns the running DokuWiki version.', |
|
98 |
true
|
|
99 |
);
|
|
100 |
||
101 |
$this->addCallback( |
|
102 |
'dokuwiki.login', |
|
103 |
'this:login', |
|
104 |
array('integer','string','string'), |
|
105 |
'Tries to login with the given credentials and sets auth cookies.', |
|
106 |
true
|
|
107 |
);
|
|
108 |
||
109 |
$this->addCallback( |
|
110 |
'dokuwiki.getPagelist', |
|
111 |
'this:readNamespace', |
|
112 |
array('struct','string','struct'), |
|
113 |
'List all pages within the given namespace.'
|
|
114 |
);
|
|
115 |
||
116 |
$this->addCallback( |
|
117 |
'dokuwiki.search', |
|
118 |
'this:search', |
|
119 |
array('struct','string'), |
|
120 |
'Perform a fulltext search and return a list of matching pages'
|
|
121 |
);
|
|
122 |
||
123 |
$this->addCallback( |
|
124 |
'dokuwiki.getTime', |
|
125 |
'time', |
|
126 |
array('int'), |
|
127 |
'Return the current time at the wiki server.'
|
|
128 |
);
|
|
129 |
||
130 |
$this->addCallback( |
|
131 |
'dokuwiki.setLocks', |
|
132 |
'this:setLocks', |
|
133 |
array('struct','struct'), |
|
134 |
'Lock or unlock pages.'
|
|
135 |
);
|
|
136 |
||
137 |
||
138 |
$this->addCallback( |
|
139 |
'dokuwiki.getTitle', |
|
140 |
'this:getTitle', |
|
141 |
array('string'), |
|
142 |
'Returns the wiki title.', |
|
143 |
true
|
|
144 |
);
|
|
145 |
||
146 |
/* Wiki API v2 http://www.jspwiki.org/wiki/WikiRPCInterface2 */
|
|
147 |
$this->addCallback( |
|
148 |
'wiki.getRPCVersionSupported', |
|
149 |
'this:wiki_RPCVersion', |
|
150 |
array('int'), |
|
151 |
'Returns 2 with the supported RPC API version.', |
|
152 |
true
|
|
153 |
);
|
|
154 |
$this->addCallback( |
|
155 |
'wiki.getPage', |
|
156 |
'this:rawPage', |
|
157 |
array('string','string'), |
|
158 |
'Get the raw Wiki text of page, latest version.'
|
|
159 |
);
|
|
160 |
$this->addCallback( |
|
161 |
'wiki.getPageVersion', |
|
162 |
'this:rawPage', |
|
163 |
array('string','string','int'), |
|
164 |
'Get the raw Wiki text of page.'
|
|
165 |
);
|
|
166 |
$this->addCallback( |
|
167 |
'wiki.getPageHTML', |
|
168 |
'this:htmlPage', |
|
169 |
array('string','string'), |
|
170 |
'Return page in rendered HTML, latest version.'
|
|
171 |
);
|
|
172 |
$this->addCallback( |
|
173 |
'wiki.getPageHTMLVersion', |
|
174 |
'this:htmlPage', |
|
175 |
array('string','string','int'), |
|
176 |
'Return page in rendered HTML.'
|
|
177 |
);
|
|
178 |
$this->addCallback( |
|
179 |
'wiki.getAllPages', |
|
180 |
'this:listPages', |
|
181 |
array('struct'), |
|
182 |
'Returns a list of all pages. The result is an array of utf8 pagenames.'
|
|
183 |
);
|
|
184 |
$this->addCallback( |
|
185 |
'wiki.getAttachments', |
|
186 |
'this:listAttachments', |
|
187 |
array('struct', 'string', 'struct'), |
|
188 |
'Returns a list of all media files.'
|
|
189 |
);
|
|
190 |
$this->addCallback( |
|
191 |
'wiki.getBackLinks', |
|
192 |
'this:listBackLinks', |
|
193 |
array('struct','string'), |
|
194 |
'Returns the pages that link to this page.'
|
|
195 |
);
|
|
196 |
$this->addCallback( |
|
197 |
'wiki.getPageInfo', |
|
198 |
'this:pageInfo', |
|
199 |
array('struct','string'), |
|
200 |
'Returns a struct with infos about the page.'
|
|
201 |
);
|
|
202 |
$this->addCallback( |
|
203 |
'wiki.getPageInfoVersion', |
|
204 |
'this:pageInfo', |
|
205 |
array('struct','string','int'), |
|
206 |
'Returns a struct with infos about the page.'
|
|
207 |
);
|
|
208 |
$this->addCallback( |
|
209 |
'wiki.getPageVersions', |
|
210 |
'this:pageVersions', |
|
211 |
array('struct','string','int'), |
|
212 |
'Returns the available revisions of the page.'
|
|
213 |
);
|
|
214 |
$this->addCallback( |
|
215 |
'wiki.putPage', |
|
216 |
'this:putPage', |
|
217 |
array('int', 'string', 'string', 'struct'), |
|
218 |
'Saves a wiki page.'
|
|
219 |
);
|
|
220 |
$this->addCallback( |
|
221 |
'wiki.listLinks', |
|
222 |
'this:listLinks', |
|
223 |
array('struct','string'), |
|
224 |
'Lists all links contained in a wiki page.'
|
|
225 |
);
|
|
226 |
$this->addCallback( |
|
227 |
'wiki.getRecentChanges', |
|
228 |
'this:getRecentChanges', |
|
229 |
array('struct','int'), |
|
230 |
'Returns a struct about all recent changes since given timestamp.'
|
|
231 |
);
|
|
232 |
$this->addCallback( |
|
233 |
'wiki.getRecentMediaChanges', |
|
234 |
'this:getRecentMediaChanges', |
|
235 |
array('struct','int'), |
|
236 |
'Returns a struct about all recent media changes since given timestamp.'
|
|
237 |
);
|
|
238 |
$this->addCallback( |
|
239 |
'wiki.aclCheck', |
|
240 |
'this:aclCheck', |
|
241 |
array('int', 'string'), |
|
242 |
'Returns the permissions of a given wiki page.'
|
|
243 |
);
|
|
244 |
$this->addCallback( |
|
245 |
'wiki.putAttachment', |
|
246 |
'this:putAttachment', |
|
247 |
array('struct', 'string', 'base64', 'struct'), |
|
248 |
'Upload a file to the wiki.'
|
|
249 |
);
|
|
250 |
$this->addCallback( |
|
251 |
'wiki.deleteAttachment', |
|
252 |
'this:deleteAttachment', |
|
253 |
array('int', 'string'), |
|
254 |
'Delete a file from the wiki.'
|
|
255 |
);
|
|
256 |
$this->addCallback( |
|
257 |
'wiki.getAttachment', |
|
258 |
'this:getAttachment', |
|
259 |
array('base64', 'string'), |
|
260 |
'Download a file from the wiki.'
|
|
261 |
);
|
|
262 |
$this->addCallback( |
|
263 |
'wiki.getAttachmentInfo', |
|
264 |
'this:getAttachmentInfo', |
|
265 |
array('struct', 'string'), |
|
266 |
'Returns a struct with infos about the attachment.'
|
|
267 |
);
|
|
268 |
||
269 |
/**
|
|
270 |
* Trigger XMLRPC_CALLBACK_REGISTER, action plugins can use this event
|
|
271 |
* to extend the XMLRPC interface and register their own callbacks.
|
|
272 |
*
|
|
273 |
* Event data:
|
|
274 |
* The XMLRPC server object:
|
|
275 |
*
|
|
276 |
* $event->data->addCallback() - register a callback, the second
|
|
277 |
* paramter has to be of the form "plugin:<pluginname>:<plugin
|
|
278 |
* method>"
|
|
279 |
*
|
|
280 |
* $event->data->callbacks - an array which holds all awaylable
|
|
281 |
* callbacks
|
|
282 |
*/
|
|
283 |
trigger_event('XMLRPC_CALLBACK_REGISTER', $this); |
|
284 |
||
285 |
$this->serve(); |
|
286 |
}
|
|
287 |
||
288 |
/**
|
|
289 |
* Return a raw wiki page
|
|
290 |
*/
|
|
291 |
function rawPage($id,$rev=''){ |
|
1.1.369
by Usman Akeju
- upgrades dokuwiki to 2010-11-07a (was 2010-11-07) |
292 |
$id = cleanID($id); |
1.9.1
by Clayton Kramer
Integrated Dokuwiki |
293 |
if(auth_quickaclcheck($id) < AUTH_READ){ |
294 |
return new IXR_Error(1, 'You are not allowed to read this page'); |
|
295 |
}
|
|
296 |
$text = rawWiki($id,$rev); |
|
297 |
if(!$text) { |
|
298 |
return pageTemplate($id); |
|
299 |
} else { |
|
300 |
return $text; |
|
301 |
}
|
|
302 |
}
|
|
303 |
||
304 |
/**
|
|
305 |
* Return a media file encoded in base64
|
|
306 |
*
|
|
307 |
* @author Gina Haeussge <osd@foosel.net>
|
|
308 |
*/
|
|
309 |
function getAttachment($id){ |
|
310 |
$id = cleanID($id); |
|
311 |
if (auth_quickaclcheck(getNS($id).':*') < AUTH_READ) |
|
312 |
return new IXR_Error(1, 'You are not allowed to read this file'); |
|
313 |
||
314 |
$file = mediaFN($id); |
|
315 |
if (!@ file_exists($file)) |
|
316 |
return new IXR_Error(1, 'The requested file does not exist'); |
|
317 |
||
318 |
$data = io_readFile($file, false); |
|
319 |
$base64 = base64_encode($data); |
|
320 |
return $base64; |
|
321 |
}
|
|
322 |
||
323 |
/**
|
|
324 |
* Return info about a media file
|
|
325 |
*
|
|
326 |
* @author Gina Haeussge <osd@foosel.net>
|
|
327 |
*/
|
|
328 |
function getAttachmentInfo($id){ |
|
329 |
$id = cleanID($id); |
|
330 |
$info = array( |
|
331 |
'lastModified' => 0, |
|
332 |
'size' => 0, |
|
333 |
);
|
|
334 |
||
335 |
$file = mediaFN($id); |
|
336 |
if ((auth_quickaclcheck(getNS($id).':*') >= AUTH_READ) && file_exists($file)){ |
|
337 |
$info['lastModified'] = new IXR_Date(filemtime($file)); |
|
338 |
$info['size'] = filesize($file); |
|
339 |
}
|
|
340 |
||
341 |
return $info; |
|
342 |
}
|
|
343 |
||
344 |
/**
|
|
345 |
* Return a wiki page rendered to html
|
|
346 |
*/
|
|
347 |
function htmlPage($id,$rev=''){ |
|
1.1.369
by Usman Akeju
- upgrades dokuwiki to 2010-11-07a (was 2010-11-07) |
348 |
$id = cleanID($id); |
1.9.1
by Clayton Kramer
Integrated Dokuwiki |
349 |
if(auth_quickaclcheck($id) < AUTH_READ){ |
350 |
return new IXR_Error(1, 'You are not allowed to read this page'); |
|
351 |
}
|
|
352 |
return p_wiki_xhtml($id,$rev,false); |
|
353 |
}
|
|
354 |
||
355 |
/**
|
|
356 |
* List all pages - we use the indexer list here
|
|
357 |
*/
|
|
358 |
function listPages(){ |
|
359 |
$list = array(); |
|
360 |
$pages = array_filter(array_filter(idx_getIndex('page', ''), |
|
361 |
'isVisiblePage'), |
|
362 |
'page_exists'); |
|
363 |
||
364 |
foreach(array_keys($pages) as $idx) { |
|
365 |
$perm = auth_quickaclcheck($pages[$idx]); |
|
366 |
if($perm < AUTH_READ) { |
|
367 |
continue; |
|
368 |
}
|
|
369 |
$page = array(); |
|
370 |
$page['id'] = trim($pages[$idx]); |
|
371 |
$page['perms'] = $perm; |
|
372 |
$page['size'] = @filesize(wikiFN($pages[$idx])); |
|
373 |
$page['lastModified'] = new IXR_Date(@filemtime(wikiFN($pages[$idx]))); |
|
374 |
$list[] = $page; |
|
375 |
}
|
|
376 |
||
377 |
return $list; |
|
378 |
}
|
|
379 |
||
380 |
/**
|
|
381 |
* List all pages in the given namespace (and below)
|
|
382 |
*/
|
|
383 |
function readNamespace($ns,$opts){ |
|
384 |
global $conf; |
|
385 |
||
386 |
if(!is_array($opts)) $opts=array(); |
|
387 |
||
388 |
$ns = cleanID($ns); |
|
389 |
$dir = utf8_encodeFN(str_replace(':', '/', $ns)); |
|
390 |
$data = array(); |
|
391 |
$opts['skipacl'] = 0; // no ACL skipping for XMLRPC |
|
392 |
search($data, $conf['datadir'], 'search_allpages', $opts, $dir); |
|
393 |
return $data; |
|
394 |
}
|
|
395 |
||
396 |
/**
|
|
397 |
* List all pages in the given namespace (and below)
|
|
398 |
*/
|
|
399 |
function search($query){ |
|
400 |
require_once(DOKU_INC.'inc/fulltext.php'); |
|
401 |
||
402 |
$regex = ''; |
|
403 |
$data = ft_pageSearch($query,$regex); |
|
404 |
$pages = array(); |
|
405 |
||
406 |
// prepare additional data
|
|
407 |
$idx = 0; |
|
408 |
foreach($data as $id => $score){ |
|
409 |
$file = wikiFN($id); |
|
410 |
||
411 |
if($idx < FT_SNIPPET_NUMBER){ |
|
412 |
$snippet = ft_snippet($id,$regex); |
|
413 |
$idx++; |
|
414 |
}else{ |
|
415 |
$snippet = ''; |
|
416 |
}
|
|
417 |
||
418 |
$pages[] = array( |
|
419 |
'id' => $id, |
|
420 |
'score' => $score, |
|
421 |
'rev' => filemtime($file), |
|
422 |
'mtime' => filemtime($file), |
|
423 |
'size' => filesize($file), |
|
424 |
'snippet' => $snippet, |
|
425 |
);
|
|
426 |
}
|
|
427 |
return $pages; |
|
428 |
}
|
|
429 |
||
430 |
/**
|
|
431 |
* Returns the wiki title.
|
|
432 |
*/
|
|
433 |
function getTitle(){ |
|
434 |
global $conf; |
|
435 |
return $conf['title']; |
|
436 |
}
|
|
437 |
||
438 |
/**
|
|
439 |
* List all media files.
|
|
440 |
*
|
|
441 |
* Available options are 'recursive' for also including the subnamespaces
|
|
442 |
* in the listing, and 'pattern' for filtering the returned files against
|
|
443 |
* a regular expression matching their name.
|
|
444 |
*
|
|
445 |
* @author Gina Haeussge <osd@foosel.net>
|
|
446 |
*/
|
|
447 |
function listAttachments($ns, $options = array()) { |
|
448 |
global $conf; |
|
449 |
global $lang; |
|
450 |
||
451 |
$ns = cleanID($ns); |
|
452 |
||
453 |
if (!is_array($options)) $options = array(); |
|
454 |
$options['skipacl'] = 0; // no ACL skipping for XMLRPC |
|
455 |
||
456 |
||
457 |
if(auth_quickaclcheck($ns.':*') >= AUTH_READ) { |
|
458 |
$dir = utf8_encodeFN(str_replace(':', '/', $ns)); |
|
459 |
||
460 |
$data = array(); |
|
461 |
search($data, $conf['mediadir'], 'search_media', $options, $dir); |
|
462 |
$len = count($data); |
|
463 |
if(!$len) return array(); |
|
464 |
||
465 |
for($i=0; $i<$len; $i++) { |
|
466 |
unset($data[$i]['meta']); |
|
467 |
$data[$i]['lastModified'] = new IXR_Date($data[$i]['mtime']); |
|
468 |
}
|
|
469 |
return $data; |
|
470 |
} else { |
|
471 |
return new IXR_Error(1, 'You are not allowed to list media files.'); |
|
472 |
}
|
|
473 |
}
|
|
474 |
||
475 |
/**
|
|
476 |
* Return a list of backlinks
|
|
477 |
*/
|
|
478 |
function listBackLinks($id){ |
|
479 |
return ft_backlinks(cleanID($id)); |
|
480 |
}
|
|
481 |
||
482 |
/**
|
|
483 |
* Return some basic data about a page
|
|
484 |
*/
|
|
485 |
function pageInfo($id,$rev=''){ |
|
1.1.369
by Usman Akeju
- upgrades dokuwiki to 2010-11-07a (was 2010-11-07) |
486 |
$id = cleanID($id); |
1.9.1
by Clayton Kramer
Integrated Dokuwiki |
487 |
if(auth_quickaclcheck($id) < AUTH_READ){ |
488 |
return new IXR_Error(1, 'You are not allowed to read this page'); |
|
489 |
}
|
|
490 |
$file = wikiFN($id,$rev); |
|
491 |
$time = @filemtime($file); |
|
492 |
if(!$time){ |
|
493 |
return new IXR_Error(10, 'The requested page does not exist'); |
|
494 |
}
|
|
495 |
||
496 |
$info = getRevisionInfo($id, $time, 1024); |
|
497 |
||
498 |
$data = array( |
|
499 |
'name' => $id, |
|
500 |
'lastModified' => new IXR_Date($time), |
|
501 |
'author' => (($info['user']) ? $info['user'] : $info['ip']), |
|
502 |
'version' => $time |
|
503 |
);
|
|
504 |
||
505 |
return ($data); |
|
506 |
}
|
|
507 |
||
508 |
/**
|
|
509 |
* Save a wiki page
|
|
510 |
*
|
|
511 |
* @author Michael Klier <chi@chimeric.de>
|
|
512 |
*/
|
|
513 |
function putPage($id, $text, $params) { |
|
514 |
global $TEXT; |
|
515 |
global $lang; |
|
516 |
global $conf; |
|
517 |
||
518 |
$id = cleanID($id); |
|
519 |
$TEXT = cleanText($text); |
|
520 |
$sum = $params['sum']; |
|
521 |
$minor = $params['minor']; |
|
522 |
||
523 |
if(empty($id)) |
|
524 |
return new IXR_Error(1, 'Empty page ID'); |
|
525 |
||
526 |
if(!page_exists($id) && trim($TEXT) == '' ) { |
|
527 |
return new IXR_ERROR(1, 'Refusing to write an empty new wiki page'); |
|
528 |
}
|
|
529 |
||
530 |
if(auth_quickaclcheck($id) < AUTH_EDIT) |
|
531 |
return new IXR_Error(1, 'You are not allowed to edit this page'); |
|
532 |
||
533 |
// Check, if page is locked
|
|
534 |
if(checklock($id)) |
|
535 |
return new IXR_Error(1, 'The page is currently locked'); |
|
536 |
||
537 |
// SPAM check
|
|
538 |
if(checkwordblock()) |
|
539 |
return new IXR_Error(1, 'Positive wordblock check'); |
|
540 |
||
541 |
// autoset summary on new pages
|
|
542 |
if(!page_exists($id) && empty($sum)) { |
|
543 |
$sum = $lang['created']; |
|
544 |
}
|
|
545 |
||
546 |
// autoset summary on deleted pages
|
|
547 |
if(page_exists($id) && empty($TEXT) && empty($sum)) { |
|
548 |
$sum = $lang['deleted']; |
|
549 |
}
|
|
550 |
||
551 |
lock($id); |
|
552 |
||
553 |
saveWikiText($id,$TEXT,$sum,$minor); |
|
554 |
||
555 |
unlock($id); |
|
556 |
||
557 |
// run the indexer if page wasn't indexed yet
|
|
558 |
if(!@file_exists(metaFN($id, '.indexed'))) { |
|
559 |
// try to aquire a lock
|
|
560 |
$lock = $conf['lockdir'].'/_indexer.lock'; |
|
561 |
while(!@mkdir($lock,$conf['dmode'])){ |
|
562 |
usleep(50); |
|
563 |
if(time()-@filemtime($lock) > 60*5){ |
|
564 |
// looks like a stale lock - remove it
|
|
565 |
@rmdir($lock); |
|
566 |
}else{ |
|
567 |
return false; |
|
568 |
}
|
|
569 |
}
|
|
570 |
if($conf['dperm']) chmod($lock, $conf['dperm']); |
|
571 |
||
572 |
// do the work
|
|
573 |
idx_addPage($id); |
|
574 |
||
575 |
// we're finished - save and free lock
|
|
576 |
io_saveFile(metaFN($id,'.indexed'),INDEXER_VERSION); |
|
577 |
@rmdir($lock); |
|
578 |
}
|
|
579 |
||
580 |
return 0; |
|
581 |
}
|
|
582 |
||
583 |
/**
|
|
584 |
* Uploads a file to the wiki.
|
|
585 |
*
|
|
586 |
* Michael Klier <chi@chimeric.de>
|
|
587 |
*/
|
|
588 |
function putAttachment($id, $file, $params) { |
|
1.1.369
by Usman Akeju
- upgrades dokuwiki to 2010-11-07a (was 2010-11-07) |
589 |
$id = cleanID($id); |
1.9.1
by Clayton Kramer
Integrated Dokuwiki |
590 |
global $conf; |
591 |
global $lang; |
|
592 |
||
593 |
$auth = auth_quickaclcheck(getNS($id).':*'); |
|
594 |
if($auth >= AUTH_UPLOAD) { |
|
595 |
if(!isset($id)) { |
|
596 |
return new IXR_ERROR(1, 'Filename not given.'); |
|
597 |
}
|
|
598 |
||
599 |
$ftmp = $conf['tmpdir'] . '/' . md5($id.clientIP()); |
|
600 |
||
601 |
// save temporary file
|
|
602 |
@unlink($ftmp); |
|
603 |
$buff = base64_decode($file); |
|
604 |
io_saveFile($ftmp, $buff); |
|
605 |
||
606 |
// get filename
|
|
607 |
list($iext, $imime,$dl) = mimetype($id); |
|
608 |
$id = cleanID($id); |
|
609 |
$fn = mediaFN($id); |
|
610 |
||
611 |
// get filetype regexp
|
|
612 |
$types = array_keys(getMimeTypes()); |
|
613 |
$types = array_map(create_function('$q','return preg_quote($q,"/");'),$types); |
|
614 |
$regex = join('|',$types); |
|
615 |
||
616 |
// because a temp file was created already
|
|
617 |
if(preg_match('/\.('.$regex.')$/i',$fn)) { |
|
618 |
//check for overwrite
|
|
619 |
$overwrite = @file_exists($fn); |
|
620 |
if($overwrite && (!$params['ow'] || $auth < AUTH_DELETE)) { |
|
621 |
return new IXR_ERROR(1, $lang['uploadexist'].'1'); |
|
622 |
}
|
|
623 |
// check for valid content
|
|
624 |
$ok = media_contentcheck($ftmp, $imime); |
|
625 |
if($ok == -1) { |
|
626 |
return new IXR_ERROR(1, sprintf($lang['uploadexist'].'2', ".$iext")); |
|
627 |
} elseif($ok == -2) { |
|
628 |
return new IXR_ERROR(1, $lang['uploadspam']); |
|
629 |
} elseif($ok == -3) { |
|
630 |
return new IXR_ERROR(1, $lang['uploadxss']); |
|
631 |
}
|
|
632 |
||
633 |
// prepare event data
|
|
634 |
$data[0] = $ftmp; |
|
635 |
$data[1] = $fn; |
|
636 |
$data[2] = $id; |
|
637 |
$data[3] = $imime; |
|
638 |
$data[4] = $overwrite; |
|
639 |
||
640 |
// trigger event
|
|
641 |
return trigger_event('MEDIA_UPLOAD_FINISH', $data, array($this, '_media_upload_action'), true); |
|
642 |
||
643 |
} else { |
|
644 |
return new IXR_ERROR(1, $lang['uploadwrong']); |
|
645 |
}
|
|
646 |
} else { |
|
647 |
return new IXR_ERROR(1, "You don't have permissions to upload files."); |
|
648 |
}
|
|
649 |
}
|
|
650 |
||
651 |
/**
|
|
652 |
* Deletes a file from the wiki.
|
|
653 |
*
|
|
654 |
* @author Gina Haeussge <osd@foosel.net>
|
|
655 |
*/
|
|
656 |
function deleteAttachment($id){ |
|
1.1.369
by Usman Akeju
- upgrades dokuwiki to 2010-11-07a (was 2010-11-07) |
657 |
$id = cleanID($id); |
1.9.1
by Clayton Kramer
Integrated Dokuwiki |
658 |
$auth = auth_quickaclcheck(getNS($id).':*'); |
659 |
if($auth < AUTH_DELETE) return new IXR_ERROR(1, "You don't have permissions to delete files."); |
|
660 |
global $conf; |
|
661 |
global $lang; |
|
662 |
||
663 |
// check for references if needed
|
|
664 |
$mediareferences = array(); |
|
665 |
if($conf['refcheck']){ |
|
666 |
$mediareferences = ft_mediause($id,$conf['refshow']); |
|
667 |
}
|
|
668 |
||
669 |
if(!count($mediareferences)){ |
|
670 |
$file = mediaFN($id); |
|
671 |
if(@unlink($file)){ |
|
672 |
addMediaLogEntry(time(), $id, DOKU_CHANGE_TYPE_DELETE); |
|
673 |
io_sweepNS($id,'mediadir'); |
|
674 |
return 0; |
|
675 |
}
|
|
676 |
//something went wrong
|
|
677 |
return new IXR_ERROR(1, 'Could not delete file'); |
|
678 |
} else { |
|
679 |
return new IXR_ERROR(1, 'File is still referenced'); |
|
680 |
}
|
|
681 |
}
|
|
682 |
||
683 |
/**
|
|
684 |
* Moves the temporary file to its final destination.
|
|
685 |
*
|
|
686 |
* Michael Klier <chi@chimeric.de>
|
|
687 |
*/
|
|
688 |
function _media_upload_action($data) { |
|
689 |
global $conf; |
|
690 |
||
691 |
if(is_array($data) && count($data)===5) { |
|
692 |
io_createNamespace($data[2], 'media'); |
|
693 |
if(rename($data[0], $data[1])) { |
|
694 |
chmod($data[1], $conf['fmode']); |
|
695 |
media_notify($data[2], $data[1], $data[3]); |
|
696 |
// add a log entry to the media changelog
|
|
697 |
if ($data[4]) { |
|
698 |
addMediaLogEntry(time(), $data[2], DOKU_CHANGE_TYPE_EDIT); |
|
699 |
} else { |
|
700 |
addMediaLogEntry(time(), $data[2], DOKU_CHANGE_TYPE_CREATE); |
|
701 |
}
|
|
702 |
return $data[2]; |
|
703 |
} else { |
|
704 |
return new IXR_ERROR(1, 'Upload failed.'); |
|
705 |
}
|
|
706 |
} else { |
|
707 |
return new IXR_ERROR(1, 'Upload failed.'); |
|
708 |
}
|
|
709 |
}
|
|
710 |
||
711 |
/**
|
|
712 |
* Returns the permissions of a given wiki page
|
|
713 |
*/
|
|
714 |
function aclCheck($id) { |
|
1.1.369
by Usman Akeju
- upgrades dokuwiki to 2010-11-07a (was 2010-11-07) |
715 |
$id = cleanID($id); |
1.9.1
by Clayton Kramer
Integrated Dokuwiki |
716 |
return auth_quickaclcheck($id); |
717 |
}
|
|
718 |
||
719 |
/**
|
|
720 |
* Lists all links contained in a wiki page
|
|
721 |
*
|
|
722 |
* @author Michael Klier <chi@chimeric.de>
|
|
723 |
*/
|
|
724 |
function listLinks($id) { |
|
1.1.369
by Usman Akeju
- upgrades dokuwiki to 2010-11-07a (was 2010-11-07) |
725 |
$id = cleanID($id); |
1.9.1
by Clayton Kramer
Integrated Dokuwiki |
726 |
if(auth_quickaclcheck($id) < AUTH_READ){ |
727 |
return new IXR_Error(1, 'You are not allowed to read this page'); |
|
728 |
}
|
|
729 |
$links = array(); |
|
730 |
||
731 |
// resolve page instructions
|
|
1.1.369
by Usman Akeju
- upgrades dokuwiki to 2010-11-07a (was 2010-11-07) |
732 |
$ins = p_cached_instructions(wikiFN($id)); |
1.9.1
by Clayton Kramer
Integrated Dokuwiki |
733 |
|
734 |
// instantiate new Renderer - needed for interwiki links
|
|
735 |
include(DOKU_INC.'inc/parser/xhtml.php'); |
|
736 |
$Renderer = new Doku_Renderer_xhtml(); |
|
737 |
$Renderer->interwiki = getInterwiki(); |
|
738 |
||
739 |
// parse parse instructions
|
|
740 |
foreach($ins as $in) { |
|
741 |
$link = array(); |
|
742 |
switch($in[0]) { |
|
743 |
case 'internallink': |
|
744 |
$link['type'] = 'local'; |
|
745 |
$link['page'] = $in[1][0]; |
|
746 |
$link['href'] = wl($in[1][0]); |
|
747 |
array_push($links,$link); |
|
748 |
break; |
|
749 |
case 'externallink': |
|
750 |
$link['type'] = 'extern'; |
|
751 |
$link['page'] = $in[1][0]; |
|
752 |
$link['href'] = $in[1][0]; |
|
753 |
array_push($links,$link); |
|
754 |
break; |
|
755 |
case 'interwikilink': |
|
756 |
$url = $Renderer->_resolveInterWiki($in[1][2],$in[1][3]); |
|
757 |
$link['type'] = 'extern'; |
|
758 |
$link['page'] = $url; |
|
759 |
$link['href'] = $url; |
|
760 |
array_push($links,$link); |
|
761 |
break; |
|
762 |
}
|
|
763 |
}
|
|
764 |
||
765 |
return ($links); |
|
766 |
}
|
|
767 |
||
768 |
/**
|
|
769 |
* Returns a list of recent changes since give timestamp
|
|
770 |
*
|
|
771 |
* @author Michael Hamann <michael@content-space.de>
|
|
772 |
* @author Michael Klier <chi@chimeric.de>
|
|
773 |
*/
|
|
774 |
function getRecentChanges($timestamp) { |
|
775 |
if(strlen($timestamp) != 10) |
|
776 |
return new IXR_Error(20, 'The provided value is not a valid timestamp'); |
|
777 |
||
778 |
$recents = getRecentsSince($timestamp); |
|
779 |
||
780 |
$changes = array(); |
|
781 |
||
782 |
foreach ($recents as $recent) { |
|
783 |
$change = array(); |
|
784 |
$change['name'] = $recent['id']; |
|
785 |
$change['lastModified'] = new IXR_Date($recent['date']); |
|
786 |
$change['author'] = $recent['user']; |
|
787 |
$change['version'] = $recent['date']; |
|
788 |
$change['perms'] = $recent['perms']; |
|
789 |
$change['size'] = @filesize(wikiFN($recent['id'])); |
|
790 |
array_push($changes, $change); |
|
791 |
}
|
|
792 |
||
793 |
if (!empty($changes)) { |
|
794 |
return $changes; |
|
795 |
} else { |
|
796 |
// in case we still have nothing at this point
|
|
797 |
return new IXR_Error(30, 'There are no changes in the specified timeframe'); |
|
798 |
}
|
|
799 |
}
|
|
800 |
||
801 |
/**
|
|
802 |
* Returns a list of recent media changes since give timestamp
|
|
803 |
*
|
|
804 |
* @author Michael Hamann <michael@content-space.de>
|
|
805 |
* @author Michael Klier <chi@chimeric.de>
|
|
806 |
*/
|
|
807 |
function getRecentMediaChanges($timestamp) { |
|
808 |
if(strlen($timestamp) != 10) |
|
809 |
return new IXR_Error(20, 'The provided value is not a valid timestamp'); |
|
810 |
||
811 |
$recents = getRecentsSince($timestamp, null, '', RECENTS_MEDIA_CHANGES); |
|
812 |
||
813 |
$changes = array(); |
|
814 |
||
815 |
foreach ($recents as $recent) { |
|
816 |
$change = array(); |
|
817 |
$change['name'] = $recent['id']; |
|
818 |
$change['lastModified'] = new IXR_Date($recent['date']); |
|
819 |
$change['author'] = $recent['user']; |
|
820 |
$change['version'] = $recent['date']; |
|
821 |
$change['perms'] = $recent['perms']; |
|
822 |
$change['size'] = @filesize(mediaFN($recent['id'])); |
|
823 |
array_push($changes, $change); |
|
824 |
}
|
|
825 |
||
826 |
if (!empty($changes)) { |
|
827 |
return $changes; |
|
828 |
} else { |
|
829 |
// in case we still have nothing at this point
|
|
830 |
return new IXR_Error(30, 'There are no changes in the specified timeframe'); |
|
831 |
}
|
|
832 |
}
|
|
833 |
||
834 |
/**
|
|
835 |
* Returns a list of available revisions of a given wiki page
|
|
836 |
*
|
|
837 |
* @author Michael Klier <chi@chimeric.de>
|
|
838 |
*/
|
|
839 |
function pageVersions($id, $first) { |
|
1.1.369
by Usman Akeju
- upgrades dokuwiki to 2010-11-07a (was 2010-11-07) |
840 |
$id = cleanID($id); |
841 |
if(auth_quickaclcheck($id) < AUTH_READ){ |
|
842 |
return new IXR_Error(1, 'You are not allowed to read this page'); |
|
843 |
}
|
|
1.9.1
by Clayton Kramer
Integrated Dokuwiki |
844 |
global $conf; |
845 |
||
846 |
$versions = array(); |
|
847 |
||
848 |
if(empty($id)) |
|
849 |
return new IXR_Error(1, 'Empty page ID'); |
|
850 |
||
851 |
$revisions = getRevisions($id, $first, $conf['recent']+1); |
|
852 |
||
853 |
if(count($revisions)==0 && $first!=0) { |
|
854 |
$first=0; |
|
855 |
$revisions = getRevisions($id, $first, $conf['recent']+1); |
|
856 |
}
|
|
857 |
||
858 |
if(count($revisions)>0 && $first==0) { |
|
859 |
array_unshift($revisions, ''); // include current revision |
|
860 |
array_pop($revisions); // remove extra log entry |
|
861 |
}
|
|
862 |
||
863 |
$hasNext = false; |
|
864 |
if(count($revisions)>$conf['recent']) { |
|
865 |
$hasNext = true; |
|
866 |
array_pop($revisions); // remove extra log entry |
|
867 |
}
|
|
868 |
||
869 |
if(!empty($revisions)) { |
|
870 |
foreach($revisions as $rev) { |
|
871 |
$file = wikiFN($id,$rev); |
|
872 |
$time = @filemtime($file); |
|
873 |
// we check if the page actually exists, if this is not the
|
|
874 |
// case this can lead to less pages being returned than
|
|
875 |
// specified via $conf['recent']
|
|
876 |
if($time){ |
|
877 |
$info = getRevisionInfo($id, $time, 1024); |
|
878 |
if(!empty($info)) { |
|
879 |
$data['user'] = $info['user']; |
|
880 |
$data['ip'] = $info['ip']; |
|
881 |
$data['type'] = $info['type']; |
|
882 |
$data['sum'] = $info['sum']; |
|
883 |
$data['modified'] = new IXR_Date($info['date']); |
|
884 |
$data['version'] = $info['date']; |
|
885 |
array_push($versions, $data); |
|
886 |
}
|
|
887 |
}
|
|
888 |
}
|
|
889 |
return $versions; |
|
890 |
} else { |
|
891 |
return array(); |
|
892 |
}
|
|
893 |
}
|
|
894 |
||
895 |
/**
|
|
896 |
* The version of Wiki RPC API supported
|
|
897 |
*/
|
|
898 |
function wiki_RPCVersion(){ |
|
899 |
return 2; |
|
900 |
}
|
|
901 |
||
902 |
||
903 |
/**
|
|
904 |
* Locks or unlocks a given batch of pages
|
|
905 |
*
|
|
906 |
* Give an associative array with two keys: lock and unlock. Both should contain a
|
|
907 |
* list of pages to lock or unlock
|
|
908 |
*
|
|
909 |
* Returns an associative array with the keys locked, lockfail, unlocked and
|
|
910 |
* unlockfail, each containing lists of pages.
|
|
911 |
*/
|
|
912 |
function setLocks($set){ |
|
913 |
$locked = array(); |
|
914 |
$lockfail = array(); |
|
915 |
$unlocked = array(); |
|
916 |
$unlockfail = array(); |
|
917 |
||
918 |
foreach((array) $set['lock'] as $id){ |
|
1.1.369
by Usman Akeju
- upgrades dokuwiki to 2010-11-07a (was 2010-11-07) |
919 |
$id = cleanID($id); |
920 |
if(auth_quickaclcheck($id) < AUTH_EDIT || checklock($id)){ |
|
1.9.1
by Clayton Kramer
Integrated Dokuwiki |
921 |
$lockfail[] = $id; |
922 |
}else{ |
|
923 |
lock($id); |
|
924 |
$locked[] = $id; |
|
925 |
}
|
|
926 |
}
|
|
927 |
||
928 |
foreach((array) $set['unlock'] as $id){ |
|
1.1.369
by Usman Akeju
- upgrades dokuwiki to 2010-11-07a (was 2010-11-07) |
929 |
$id = cleanID($id); |
930 |
if(auth_quickaclcheck($id) < AUTH_EDIT || !unlock($id)){ |
|
931 |
$unlockfail[] = $id; |
|
932 |
}else{ |
|
1.9.1
by Clayton Kramer
Integrated Dokuwiki |
933 |
$unlocked[] = $id; |
934 |
}
|
|
935 |
}
|
|
936 |
||
937 |
return array( |
|
938 |
'locked' => $locked, |
|
939 |
'lockfail' => $lockfail, |
|
940 |
'unlocked' => $unlocked, |
|
941 |
'unlockfail' => $unlockfail, |
|
942 |
);
|
|
943 |
}
|
|
944 |
||
945 |
function getAPIVersion(){ |
|
946 |
return DOKU_XMLRPC_API_VERSION; |
|
947 |
}
|
|
948 |
||
949 |
function login($user,$pass){ |
|
950 |
global $conf; |
|
951 |
global $auth; |
|
952 |
if(!$conf['useacl']) return 0; |
|
953 |
if(!$auth) return 0; |
|
954 |
if($auth->canDo('external')){ |
|
955 |
return $auth->trustExternal($user,$pass,false); |
|
956 |
}else{ |
|
957 |
return auth_login($user,$pass,false,true); |
|
958 |
}
|
|
959 |
}
|
|
960 |
||
961 |
||
962 |
}
|
|
963 |
||
964 |
$server = new dokuwiki_xmlrpc_server(); |
|
965 |
||
966 |
// vim:ts=4:sw=4:et:enc=utf-8:
|