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