]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/XmlRpcServer.php
add putPage from Arnaud Fontaine, with auth checks from rurban
[SourceForge/phpwiki.git] / lib / XmlRpcServer.php
1 <?php
2 // $Id: XmlRpcServer.php,v 1.13 2005-01-21 14:10:36 rurban Exp $
3 /* Copyright (C) 2002, Lawrence Akka <lakka@users.sourceforge.net>
4  * Copyright (C) 2004, 2005 $ThePhpWikiProgrammingTeam
5  *
6  * LICENCE
7  * =======
8  * This file is part of PhpWiki.
9  * 
10  * PhpWiki is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * PhpWiki is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with PhpWiki; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  * LIBRARY USED - POSSIBLE PROBLEMS
25  * ================================
26  * 
27  * This file provides an XML-RPC interface for PhpWiki. 
28  * It checks for the existence of the xmlrpc-epi c library by Dan Libby 
29  * (see http://uk2.php.net/manual/en/ref.xmlrpc.php), and falls back to 
30  * the slower PHP counterpart XML-RPC library by Edd Dumbill. 
31  * See http://xmlrpc.usefulinc.com/php.html for details.
32  * 
33  * INTERFACE SPECIFICTION
34  * ======================
35  *  
36  * The interface specification is that discussed at 
37  * http://www.ecyrd.com/JSPWiki/Wiki.jsp?page=WikiRPCInterface
38  * 
39  * See also http://www.usemod.com/cgi-bin/mb.pl?XmlRpc
40  * or http://www.devshed.com/c/a/PHP/Using-XMLRPC-with-PHP/
41  * 
42  * Note: All XMLRPC methods are automatically prefixed with "wiki."
43  *       eg. "wiki.getAllPages"
44 */
45
46 /*
47 ToDo:
48         Remove all warnings from xmlrpc.inc 
49         Return list of external links in listLinks
50         Support RSS2 cloud subscription
51 Done:
52         Test hwiki.jar xmlrpc interface (java visualization plugin)
53         Make use of the xmlrpc extension if found. http://xmlrpc-epi.sourceforge.net/
54         Resolved namespace conflicts
55 */
56
57 // Intercept GET requests from confused users.  Only POST is allowed here!
58 // There is some indication that $HTTP_SERVER_VARS is deprecated in php > 4.1.0
59 // in favour of $_Server, but as far as I know, it still works.
60 if ($GLOBALS['HTTP_SERVER_VARS']['REQUEST_METHOD'] != "POST")
61 {
62     die('This is the address of the XML-RPC interface.' .
63         '  You must use XML-RPC calls to access information here');
64 }
65
66 // All these global declarations make it so that this file
67 // (XmlRpcServer.php) can be included within a function body
68 // (not in global scope), and things will still work....
69
70 global $xmlrpcI4, $xmlrpcInt, $xmlrpcBoolean, $xmlrpcDouble, $xmlrpcString;
71 global $xmlrpcDateTime, $xmlrpcBase64, $xmlrpcArray, $xmlrpcStruct;
72 global $xmlrpcTypes;
73 global $xmlEntities;
74 global $xmlrpcerr, $xmlrpcstr;
75 global $xmlrpc_defencoding;
76 global $xmlrpcName, $xmlrpcVersion;
77 global $xmlrpcerruser, $xmlrpcerrxml;
78 global $xmlrpc_backslash;
79 global $_xh;
80
81 if (loadPhpExtension('xmlrpc')) { // fast c lib
82     define('XMLRPC_EXT_LOADED', true);
83
84     global $xmlrpc_util_path;
85     $xmlrpc_util_path = dirname(__FILE__)."/XMLRPC/";
86     include_once("lib/XMLRPC/xmlrpc_emu.inc"); 
87     global $_xmlrpcs_debug;
88     include_once("lib/XMLRPC/xmlrpcs_emu.inc");
89
90  } else { // slow php lib
91     define('XMLRPC_EXT_LOADED', true);
92
93     // Include the php XML-RPC library
94     include_once("lib/XMLRPC/xmlrpc.inc");
95
96     global $_xmlrpcs_dmap;
97     global $_xmlrpcs_debug;
98     include_once("lib/XMLRPC/xmlrpcs.inc");
99 }
100  
101
102 //  API version
103 define ("WIKI_XMLRPC_VERSION", 2);
104
105 /**
106  * Helper function:  Looks up a page revision (most recent by default) in the wiki database
107  * 
108  * @param xmlrpcmsg $params :  string pagename [int version]
109  * @return WikiDB _PageRevision object, or false if no such page
110  */
111
112 function _getPageRevision ($params)
113 {
114     global $request;
115     $ParamPageName = $params->getParam(0);
116     $ParamVersion = $params->getParam(1);
117     $pagename = short_string_decode($ParamPageName->scalarval());
118     $version =  ($ParamVersion) ? ($ParamVersion->scalarval()):(0);
119     // FIXME:  test for version <=0 ??
120     $dbh = $request->getDbh();
121     if ($dbh->isWikiPage($pagename)) {
122         $page = $dbh->getPage($pagename);
123         if (!$version) {
124             $revision = $page->getCurrentRevision();
125         } else {
126             $revision = $page->getRevision($version);
127         } 
128         return $revision;
129     } 
130     return false;
131
132
133 /*
134  * Helper functions for encoding/decoding strings.
135  *
136  * According to WikiRPC spec, all returned strings take one of either
137  * two forms.  Short strings (page names, and authors) are converted to
138  * UTF-8, then rawurlencode()d, and returned as XML-RPC <code>strings</code>.
139  * Long strings (page content) are converted to UTF-8 then returned as
140  * XML-RPC <code>base64</code> binary objects.
141  */
142
143 /**
144  * Urlencode ASCII control characters.
145  *
146  * (And control characters...)
147  *
148  * @param string $str
149  * @return string
150  * @see urlencode
151  */
152 function UrlencodeControlCharacters($str) {
153     return preg_replace('/([\x00-\x1F])/e', "urlencode('\\1')", $str);
154 }
155
156 /**
157  * Convert a short string (page name, author) to xmlrpcval.
158  */
159 function short_string ($str) {
160     return new xmlrpcval(UrlencodeControlCharacters(utf8_encode($str)), 'string');
161 }
162
163 /**
164  * Convert a large string (page content) to xmlrpcval.
165  */
166 function long_string ($str) {
167     return new xmlrpcval(utf8_encode($str), 'base64');
168 }
169
170 /**
171  * Decode a short string (e.g. page name)
172  */
173 function short_string_decode ($str) {
174     return utf8_decode(urldecode($str));
175 }
176
177 /**
178  * Get an xmlrpc "No such page" error message
179  */
180 function NoSuchPage ($pagename='') 
181 {
182     global $xmlrpcerruser;
183     return new xmlrpcresp(0, $xmlrpcerruser + 1, "No such page ".$pagename);
184 }
185
186
187 // ****************************************************************************
188 // Main API functions follow
189 // ****************************************************************************
190 global $wiki_dmap;
191
192 /**
193  * int getRPCVersionSupported(): Returns 1 for this version of the API 
194  */
195 $wiki_dmap['getRPCVersionSupported']
196 = array('signature'     => array(array($xmlrpcInt)),
197         'documentation' => 'Get the version of the wiki API',
198         'function'      => 'getRPCVersionSupported');
199
200 // The function must be a function in the global scope which services the XML-RPC
201 // method.
202 function getRPCVersionSupported($params)
203 {
204     return new xmlrpcresp(new xmlrpcval((integer)WIKI_XMLRPC_VERSION, "int"));
205 }
206
207 /**
208  * array getRecentChanges(Date timestamp) : Get list of changed pages since 
209  * timestamp, which should be in UTC. The result is an array, where each element
210  * is a struct: 
211  *     name (string) : Name of the page. The name is UTF-8 with URL encoding to make it ASCII. 
212  *     lastModified (date) : Date of last modification, in UTC. 
213  *     author (string) : Name of the author (if available). Again, name is UTF-8 with URL encoding. 
214  *         version (int) : Current version. 
215  * A page MAY be specified multiple times. A page MAY NOT be specified multiple 
216  * times with the same modification date.
217  */
218 $wiki_dmap['getRecentChanges']
219 = array('signature'     => array(array($xmlrpcArray, $xmlrpcDateTime)),
220         'documentation' => 'Get a list of changed pages since [timestamp]',
221         'function'      => 'getRecentChanges');
222
223 function getRecentChanges($params)
224 {
225     global $request;
226     // Get the first parameter as an ISO 8601 date. Assume UTC
227     $encoded_date = $params->getParam(0);
228     $datetime = iso8601_decode($encoded_date->scalarval(), 1);
229     $dbh = $request->getDbh();
230     $pages = array();
231     $iterator = $dbh->mostRecent(array('since' => $datetime));
232     while ($page = $iterator->next()) {
233         // $page contains a WikiDB_PageRevision object
234         // no need to url encode $name, because it is already stored in that format ???
235         $name = short_string($page->getPageName());
236         $lastmodified = new xmlrpcval(iso8601_encode($page->get('mtime')), "dateTime.iso8601");
237         $author = short_string($page->get('author'));
238         $version = new xmlrpcval($page->getVersion(), 'int');
239
240         // Build an array of xmlrpc structs
241         $pages[] = new xmlrpcval(array('name' => $name, 
242                                        'lastModified' => $lastmodified,
243                                        'author' => $author,
244                                        'version' => $version),
245                                  'struct');
246     } 
247     return new xmlrpcresp(new xmlrpcval($pages, "array"));
248
249
250
251 /**
252  * base64 getPage( String pagename ): Get the raw Wiki text of page, latest version. 
253  * Page name must be UTF-8, with URL encoding. Returned value is a binary object,
254  * with UTF-8 encoded page data.
255  */
256 $wiki_dmap['getPage']
257 = array('signature'     => array(array($xmlrpcBase64, $xmlrpcString)),
258         'documentation' => 'Get the raw Wiki text of the current version of a page',
259         'function'      => 'getPage');
260
261 function getPage($params)
262 {
263     $revision = _getPageRevision($params);
264
265     if (! $revision ) {
266         $ParamPageName = $params->getParam(0);
267         $pagename = short_string_decode($ParamPageName->scalarval());
268         return NoSuchPage($pagename);
269     }
270
271     return new xmlrpcresp(long_string($revision->getPackedContent()));
272 }
273  
274
275 /**
276  * base64 getPageVersion( String pagename, int version ): Get the raw Wiki text of page.
277  * Returns UTF-8, expects UTF-8 with URL encoding.
278  */
279 $wiki_dmap['getPageVersion']
280 = array('signature'     => array(array($xmlrpcBase64, $xmlrpcString, $xmlrpcInt)),
281         'documentation' => 'Get the raw Wiki text of a page version',
282         'function'      => 'getPageVersion');
283
284 function getPageVersion($params)
285 {
286     // error checking is done in getPage
287     return getPage($params);
288
289
290 /**
291  * base64 getPageHTML( String pagename ): Return page in rendered HTML. 
292  * Returns UTF-8, expects UTF-8 with URL encoding.
293  */
294
295 $wiki_dmap['getPageHTML']
296 = array('signature'     => array(array($xmlrpcBase64, $xmlrpcString)),
297         'documentation' => 'Get the current version of a page rendered in HTML',
298         'function'      => 'getPageHTML');
299
300 function getPageHTML($params)
301 {
302     $revision = _getPageRevision($params);
303     if (!$revision)
304         return NoSuchPage();
305     
306     $content = $revision->getTransformedContent();
307     $html = $content->asXML();
308     // HACK: Get rid of outer <div class="wikitext">
309     if (preg_match('/^\s*<div class="wikitext">/', $html, $m1)
310         && preg_match('@</div>\s*$@', $html, $m2)) {
311         $html = substr($html, strlen($m1[0]), -strlen($m2[0]));
312     }
313
314     return new xmlrpcresp(long_string($html));
315
316
317 /**
318  * base64 getPageHTMLVersion( String pagename, int version ): Return page in rendered HTML, UTF-8.
319  */
320 $wiki_dmap['getPageHTMLVersion']
321 = array('signature'     => array(array($xmlrpcBase64, $xmlrpcString, $xmlrpcInt)),
322         'documentation' => 'Get a version of a page rendered in HTML',
323         'function'      => 'getPageHTMLVersion');
324
325 function getPageHTMLVersion($params)
326 {
327     return getPageHTML($params);
328
329
330 /**
331  * getAllPages(): Returns a list of all pages. The result is an array of strings.
332  */
333 $wiki_dmap['getAllPages']
334 = array('signature'     => array(array($xmlrpcArray)),
335         'documentation' => 'Returns a list of all pages as an array of strings', 
336         'function'      => 'getAllPages');
337
338 function getAllPages($params)
339 {
340     global $request;
341     $dbh = $request->getDbh();
342     $iterator = $dbh->getAllPages();
343     $pages = array();
344     while ($page = $iterator->next()) {
345         $pages[] = short_string($page->getName());
346     } 
347     return new xmlrpcresp(new xmlrpcval($pages, "array"));
348
349
350 /**
351  * struct getPageInfo( string pagename ) : returns a struct with elements: 
352  *   name (string): the canonical page name 
353  *   lastModified (date): Last modification date 
354  *   version (int): current version 
355  *       author (string): author name 
356  */
357 $wiki_dmap['getPageInfo']
358 = array('signature'     => array(array($xmlrpcStruct, $xmlrpcString)),
359         'documentation' => 'Gets info about the current version of a page',
360         'function'      => 'getPageInfo');
361
362 function getPageInfo($params)
363 {
364     $revision = _getPageRevision($params);
365     if (!$revision)
366         return NoSuchPage();
367     
368     $name = short_string($revision->getPageName());
369     $version = new xmlrpcval ($revision->getVersion(), "int");
370     $lastmodified = new xmlrpcval(iso8601_encode($revision->get('mtime'), 0),
371                                   "dateTime.iso8601");
372     $author = short_string($revision->get('author'));
373         
374     return new xmlrpcresp(new xmlrpcval(array('name' => $name, 
375                                               'lastModified' => $lastmodified,
376                                               'version' => $version, 
377                                               'author' => $author), 
378                                         "struct"));
379
380
381 /**
382  * struct getPageInfoVersion( string pagename, int version ) : returns
383  * a struct just like plain getPageInfo(), but this time for a
384  * specific version.
385  */
386 $wiki_dmap['getPageInfoVersion']
387 = array('signature'     => array(array($xmlrpcStruct, $xmlrpcString, $xmlrpcInt)),
388         'documentation' => 'Gets info about a page version',
389         'function'      => 'getPageInfoVersion');
390
391 function getPageInfoVersion($params)
392 {
393     return getPageInfo($params);
394 }
395
396  
397 /*  array listLinks( string pagename ): Lists all links for a given page. The
398  *  returned array contains structs, with the following elements: 
399  *       name (string) : The page name or URL the link is to. 
400  *       type (int) : The link type. Zero (0) for internal Wiki link,
401  *         one (1) for external link (URL - image link, whatever).
402  */
403 $wiki_dmap['listLinks']
404 = array('signature'     => array(array($xmlrpcArray, $xmlrpcString)),
405         'documentation' => 'Lists all links for a given page',
406         'function'      => 'listLinks');
407
408 function listLinks($params)
409 {
410     global $request;
411     
412     $ParamPageName = $params->getParam(0);
413     $pagename = short_string_decode($ParamPageName->scalarval());
414     $dbh = $request->getDbh();
415     if (! $dbh->isWikiPage($pagename))
416         return NoSuchPage($pagename);
417
418     $page = $dbh->getPage($pagename);
419     
420     // The fast WikiDB method. below is the slow method which goes through the formatter
421     // NB no clean way to extract a list of external links yet, so
422     // only internal links returned.  i.e. all type 'local'.
423     $linkiterator = $page->getPageLinks();
424     $linkstruct = array();
425     while ($currentpage = $linkiterator->next()) {
426         $currentname = $currentpage->getName();
427         // Compute URL to page
428         $args = array();
429         // How to check external links?
430         if (!$currentpage->exists()) $args['action'] = 'edit';
431
432         // FIXME: Autodetected value of VIRTUAL_PATH wrong,
433         // this make absolute URLs constructed by WikiURL wrong.
434         // Also, if USE_PATH_INFO is false, WikiURL is wrong
435         // due to its use of SCRIPT_NAME.
436         //$use_abspath = USE_PATH_INFO && ! preg_match('/RPC2.php$/', VIRTUAL_PATH);
437         
438         // USE_PATH_INFO must be defined in index.php or config.ini but not before, 
439         // otherwise it is ignored and xmlrpc urls are wrong.
440         // SCRIPT_NAME here is always .../RPC2.php
441         if (USE_PATH_INFO and !$args) {
442             $url = preg_replace('/%2f/i', '/', rawurlencode($currentname));
443         } elseif (!USE_PATH_INFO) {
444             $url = str_replace("/RPC2.php","/index.php", WikiURL($currentname, $args, true));
445         } else {
446             $url = WikiURL($currentname, $args);
447         }
448         $linkstruct[] = new xmlrpcval(array('page'=> short_string($currentname),
449                                             'type'=> new xmlrpcval('local', 'string'),
450                                             'href' => short_string($url)),
451                                       "struct");
452     }
453    
454     /*
455     $current = $page->getCurrentRevision();
456     $content = $current->getTransformedContent();
457     $links = $content->getLinkInfo();
458     foreach ($links as $link) {
459         // We used to give an href for unknown pages that
460         // included action=edit.  I think that's probably the
461         // wrong thing to do.
462         $linkstruct[] = new xmlrpcval(array('page'=> short_string($link->page),
463                                             'type'=> new xmlrpcval($link->type, 'string'),
464                                             'href' => short_string($link->href),
465                                             //'pageref' => short_string($link->pageref),
466                                             ),
467                                       "struct");
468     }
469     */
470     return new xmlrpcresp(new xmlrpcval ($linkstruct, "array"));
471
472
473 /** 
474  * struct putPage(String pagename, String content, [String author[, String password]})
475  * returns a struct with elements: 
476  *   code (int): 200 on success, 400 or 401 on failure
477  *   message (string): success or failure message
478  *   version (int): version of new page
479  *
480  * @author: Arnaud Fontaine, Reini Urban
481  */
482 $wiki_dmap['putPage']
483 = array('signature'     => array(array($xmlrpcStruct, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString)),
484         'documentation' => 'put the raw Wiki text into a page as new version',
485         'function'      => 'putPage');
486
487 function _getUser($userid='') {
488     global $request;
489     
490     if (! $userid ) {
491         if (!isset($_SERVER))
492             $_SERVER =& $GLOBALS['HTTP_SERVER_VARS'];
493         if (!isset($_ENV))
494             $_ENV =& $GLOBALS['HTTP_ENV_VARS'];
495         if (isset($_SERVER['REMOTE_USER']))
496             $userid = $_SERVER['REMOTE_USER'];
497         elseif (isset($_ENV['REMOTE_USER']))
498             $userid = $_ENV['REMOTE_USER'];
499         elseif (isset($_SERVER['REMOTE_ADDR']))
500             $userid = $_SERVER['REMOTE_ADDR'];
501         elseif (isset($_ENV['REMOTE_ADDR']))
502             $userid = $_ENV['REMOTE_ADDR'];
503         elseif (isset($GLOBALS['REMOTE_ADDR']))
504             $userid = $GLOBALS['REMOTE_ADDR'];
505     }
506
507     if (ENABLE_USER_NEW) {
508         return WikiUser($userid);
509     } else {
510         return new WikiUser($request, $userid);
511     }
512 }
513         
514 function putPage($params) {
515     global $request;
516
517     $ParamPageName = $params->getParam(0);
518     $ParamContent = $params->getParam(1);
519     $pagename = short_string_decode($ParamPageName->scalarval());
520     $content = short_string_decode($ParamContent->scalarval());
521     $passwd = '';
522     if (count($params->params) > 2) {
523         $ParamAuthor = $params->getParam(2);
524         $userid = short_string_decode($ParamAuthor->scalarval());
525         if (count($params->params) > 3) {
526             $ParamPassword = $params->getParam(3);
527             $passwd = short_string_decode($ParamPassword->scalarval());
528         }
529     } else {
530         $userid = $request->_user->_userid;
531     }
532     $request->_user = _getUser($userid);
533     $request->_user->_group = $request->getGroup();
534     $$user = $request->_user->AuthCheck($userid, $passwd);
535                                          
536     if (! mayAccessPage ('edit', $pagename)) {
537         return new xmlrpcresp(
538                               new xmlrpcval(
539                                             array('code' => new xmlrpcval(401, "int"), 
540                                                   'version' => new xmlrpcval(0, "int"), 
541                                                   'message' => 
542                                                   short_string("no permission for "
543                                                                .$request->_user->UserName())), 
544                                             "struct"));
545     }
546
547     $now = time();
548     $dbh = $request->getDbh();
549     $page = $dbh->getPage($pagename);
550     $current = $page->getCurrentRevision();
551     $content = trim($content);
552     $version = $current->getVersion();
553     // $version = -1 will force create a new version
554     if ($current->getPackedContent() != $content) {
555         $init_meta = array('ctime' => $now,
556                            'creator' => $userid,
557                            'creator_id' => $userid,
558                            );
559         $version_meta = array('author' => $userid,
560                               'author_id' => $userid,
561                               'markup' => 2.0,
562                               'summary' => isset($summary) ? $summary : _("xml-rpc change"),
563                               'mtime' => $now,
564                               'pagetype' => 'wikitext',
565                               'wikitext' => $init_meta,
566                               );
567         $version++;
568         $res = $page->save($content, $version, $version_meta);
569         if ($res)
570             $message = "Page $pagename version $version created";
571         else
572             $message = "Problem creating version $version of page $pagename";
573     } else {
574         $res = 0;
575         $message = $message = "Page $pagename unchanged";
576     }
577     return new xmlrpcresp(new xmlrpcval(array('code'    => new xmlrpcval($res ? 200 : 400, "int"), 
578                                               'version' => new xmlrpcval($version, "int"), 
579                                               'message' => short_string($message)), 
580                                         "struct"));
581 }
582
583 /**
584  * Publish-Subscribe
585  * Client subscribes to a RecentChanges-like channel, getting a short 
586  * callback notification on every change. Like PageChangeNotification, just shorter 
587  * and more complicated
588  * RSS2 support (not yet), since radio userland's rss-0.92. now called RSS2.
589  * BTW: Radio Userland deprecated this interface.
590  *
591  * boolean wiki.rssPleaseNotify ( notifyProcedure, port, path, protocol, urlList )
592  *   returns: true or false 
593  *
594  * Check of the channel behind the rssurl has a cloud element, 
595  * if the client has a direct IP connection (no NAT),
596  * register the client on the WikiDB notification handler
597  *
598  * http://backend.userland.com/publishSubscribeWalkthrough
599  * http://www.soapware.org/xmlStorageSystem#rssPleaseNotify
600  * http://www.thetwowayweb.com/soapmeetsrss#rsscloudInterface
601  */
602 $wiki_dmap['rssPleaseNotify']
603 = array('signature'     => array(array($xmlrpcBoolean, $xmlrpcStruct)),
604         'documentation' => 'RSS2 change notification subscriber channel',
605         'function'      => 'rssPleaseNotify');
606
607 function rssPleaseNotify($params)
608 {
609     // register the clients IP
610     return new xmlrpcresp(new xmlrpcval (0, "boolean"));
611 }
612
613 /*
614  *  String wiki.rssPleaseNotify ( username )
615  *  returns: true or false 
616
617  */
618 $wiki_dmap['mailPasswordToUser']
619 = array('signature'     => array(array($xmlrpcBoolean, $xmlrpcString)),
620         'documentation' => 'RSS2 user management helper',
621         'function'      => 'mailPasswordToUser');
622
623 function mailPasswordToUser($params)
624 {
625     global $request;
626     $ParamUserid = $params->getParam(0);
627     $userid = short_string_decode($ParamUserid->scalarval());
628     $request->_user = _getUser($userid);
629     //$request->_prefs =& $request->_user->_prefs;
630     $email = $request->getPref('email');
631     $success = 0;
632     if ($email) {
633         $body = WikiURL('') . "\nPassword: " . $request->getPref('passwd');
634         $success = mail($email, "[".WIKI_NAME."} Password Request", 
635                         $body);
636     }
637     return new xmlrpcresp(new xmlrpcval ($success, "boolean"));
638 }
639  
640 /** 
641  * Construct the server instance, and set up the dispatch map, 
642  * which maps the XML-RPC methods on to the wiki functions.
643  * Provide the "wiki." prefix to each function
644  */
645 class XmlRpcServer extends xmlrpc_server
646 {
647     function XmlRpcServer ($request = false) {
648         global $wiki_dmap;
649         foreach ($wiki_dmap as $name => $val)
650             $dmap['wiki.' . $name] = $val;
651
652         $this->xmlrpc_server($dmap, 0 /* delay service*/);
653     }
654
655     function service () {
656         global $ErrorManager;
657
658         $ErrorManager->pushErrorHandler(new WikiMethodCb($this, '_errorHandler'));
659         xmlrpc_server::service();
660         $ErrorManager->popErrorHandler();
661     }
662     
663     function _errorHandler ($e) {
664         $msg = htmlspecialchars($e->asString());
665         // '--' not allowed within xml comment
666         $msg = str_replace('--', '&#45;&#45;', $msg);
667         if (function_exists('xmlrpc_debugmsg'))
668             xmlrpc_debugmsg($msg);
669         return true;
670     }
671 }
672
673
674 // (c-file-style: "gnu")
675 // Local Variables:
676 // mode: php
677 // tab-width: 8
678 // c-basic-offset: 4
679 // c-hanging-comment-ender-p: nil
680 // indent-tabs-mode: nil
681 // End:   
682 ?>