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