Projet

Général

Profil

Télécharger (22 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / xmlrpc_server.inc @ 859a5304

1
<?php
2

    
3
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4

    
5
/**
6
 * Server commands for our PHP implementation of the XML-RPC protocol
7
 *
8
 * This is a PEAR-ified version of Useful inc's XML-RPC for PHP.
9
 * It has support for HTTP transport, proxies and authentication.
10
 *
11
 * PHP versions 4 and 5
12
 *
13
 * @category   Web Services
14
 * @package    XML_RPC
15
 * @author     Edd Dumbill <edd@usefulinc.com>
16
 * @author     Stig Bakken <stig@php.net>
17
 * @author     Martin Jansen <mj@php.net>
18
 * @author     Daniel Convissor <danielc@php.net>
19
 * @copyright  1999-2001 Edd Dumbill, 2001-2010 The PHP Group
20
 * @license    http://www.php.net/license/3_01.txt  PHP License
21
 * @version    SVN: $Id: Server.php 300961 2010-07-03 02:17:34Z danielc $
22
 * @link       http://pear.php.net/package/XML_RPC
23
 */
24

    
25

    
26
/**
27
 * Pull in the XML_RPC class
28
 */
29
require_once 'xmlrpc_client.inc';
30

    
31

    
32
/**
33
 * signature for system.listMethods: return = array,
34
 * parameters = a string or nothing
35
 * @global array $GLOBALS['XML_RPC_Server_listMethods_sig']
36
 */
37
$GLOBALS['XML_RPC_Server_listMethods_sig'] = array(
38
    array($GLOBALS['XML_RPC_Array'],
39
          $GLOBALS['XML_RPC_String']
40
    ),
41
    array($GLOBALS['XML_RPC_Array'])
42
);
43

    
44
/**
45
 * docstring for system.listMethods
46
 * @global string $GLOBALS['XML_RPC_Server_listMethods_doc']
47
 */
48
$GLOBALS['XML_RPC_Server_listMethods_doc'] = gettext('This method lists all the'
49
        . ' methods that the XML-RPC server knows how to dispatch');
50

    
51
/**
52
 * signature for system.methodSignature: return = array,
53
 * parameters = string
54
 * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig']
55
 */
56
$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array(
57
    array($GLOBALS['XML_RPC_Array'],
58
          $GLOBALS['XML_RPC_String']
59
    )
60
);
61

    
62
/**
63
 * docstring for system.methodSignature
64
 * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc']
65
 */
66
$GLOBALS['XML_RPC_Server_methodSignature_doc'] = gettext('Returns an array of known'
67
        . ' signatures (an array of arrays) for the method name passed. If'
68
        . ' no signatures are known, returns a none-array (test for type !='
69
        . ' array to detect missing signature)');
70

    
71
/**
72
 * signature for system.methodHelp: return = string,
73
 * parameters = string
74
 * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig']
75
 */
76
$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array(
77
    array($GLOBALS['XML_RPC_String'],
78
          $GLOBALS['XML_RPC_String']
79
    )
80
);
81

    
82
/**
83
 * docstring for methodHelp
84
 * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc']
85
 */
86
$GLOBALS['XML_RPC_Server_methodHelp_doc'] = gettext('Returns help text if defined'
87
        . ' for the method passed, otherwise returns an empty string');
88

    
89
/**
90
 * dispatch map for the automatically declared XML-RPC methods.
91
 * @global array $GLOBALS['XML_RPC_Server_dmap']
92
 */
93
$GLOBALS['XML_RPC_Server_dmap'] = array(
94
    'system.listMethods' => array(
95
        'function'  => 'XML_RPC_Server_listMethods',
96
        'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'],
97
        'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc']
98
    ),
99
    'system.methodHelp' => array(
100
        'function'  => 'XML_RPC_Server_methodHelp',
101
        'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'],
102
        'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc']
103
    ),
104
    'system.methodSignature' => array(
105
        'function'  => 'XML_RPC_Server_methodSignature',
106
        'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'],
107
        'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc']
108
    )
109
);
110

    
111
/**
112
 * @global string $GLOBALS['XML_RPC_Server_debuginfo']
113
 */
114
$GLOBALS['XML_RPC_Server_debuginfo'] = '';
115

    
116

    
117
/**
118
 * Lists all the methods that the XML-RPC server knows how to dispatch
119
 *
120
 * @return object  a new XML_RPC_Response object
121
 */
122
function XML_RPC_Server_listMethods($server, $m)
123
{
124
    global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
125

    
126
    $v = new XML_RPC_Value();
127
    $outAr = array();
128
    foreach ($server->dmap as $key => $val) {
129
        $outAr[] = new XML_RPC_Value($key, 'string');
130
    }
131
    foreach ($XML_RPC_Server_dmap as $key => $val) {
132
        $outAr[] = new XML_RPC_Value($key, 'string');
133
    }
134
    $v->addArray($outAr);
135
    return new XML_RPC_Response($v);
136
}
137

    
138
/**
139
 * Returns an array of known signatures (an array of arrays)
140
 * for the given method
141
 *
142
 * If no signatures are known, returns a none-array
143
 * (test for type != array to detect missing signature)
144
 *
145
 * @return object  a new XML_RPC_Response object
146
 */
147
function XML_RPC_Server_methodSignature($server, $m)
148
{
149
    global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
150

    
151
    $methName = $m->getParam(0);
152
    $methName = $methName->scalarval();
153
    if (strpos($methName, 'system.') === 0) {
154
        $dmap = $XML_RPC_Server_dmap;
155
        $sysCall = 1;
156
    } else {
157
        $dmap = $server->dmap;
158
        $sysCall = 0;
159
    }
160
    //  print "<!-- ${methName} -->\n";
161
    if (isset($dmap[$methName])) {
162
        if ($dmap[$methName]['signature']) {
163
            $sigs = array();
164
            $thesigs = $dmap[$methName]['signature'];
165
            for ($i = 0; $i < sizeof($thesigs); $i++) {
166
                $cursig = array();
167
                $inSig = $thesigs[$i];
168
                for ($j = 0; $j < sizeof($inSig); $j++) {
169
                    $cursig[] = new XML_RPC_Value($inSig[$j], 'string');
170
                }
171
                $sigs[] = new XML_RPC_Value($cursig, 'array');
172
            }
173
            $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array'));
174
        } else {
175
            $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string'));
176
        }
177
    } else {
178
        $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'],
179
                                  $XML_RPC_str['introspect_unknown']);
180
    }
181
    return $r;
182
}
183

    
184
/**
185
 * Returns help text if defined for the method passed, otherwise returns
186
 * an empty string
187
 *
188
 * @return object  a new XML_RPC_Response object
189
 */
190
function XML_RPC_Server_methodHelp($server, $m)
191
{
192
    global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap;
193

    
194
    $methName = $m->getParam(0);
195
    $methName = $methName->scalarval();
196
    if (strpos($methName, 'system.') === 0) {
197
        $dmap = $XML_RPC_Server_dmap;
198
        $sysCall = 1;
199
    } else {
200
        $dmap = $server->dmap;
201
        $sysCall = 0;
202
    }
203

    
204
    if (isset($dmap[$methName])) {
205
        if ($dmap[$methName]['docstring']) {
206
            $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']),
207
                                                        'string');
208
        } else {
209
            $r = new XML_RPC_Response(new XML_RPC_Value('', 'string'));
210
        }
211
    } else {
212
        $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'],
213
                                     $XML_RPC_str['introspect_unknown']);
214
    }
215
    return $r;
216
}
217

    
218
/**
219
 * @return void
220
 */
221
function XML_RPC_Server_debugmsg($m)
222
{
223
    global $XML_RPC_Server_debuginfo;
224
    $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n";
225
}
226

    
227

    
228
/**
229
 * A server for receiving and replying to XML RPC requests
230
 *
231
 * <code>
232
 * $server = new XML_RPC_Server(
233
 *     array(
234
 *         'isan8' =>
235
 *             array(
236
 *                 'function' => 'is_8',
237
 *                 'signature' =>
238
 *                      array(
239
 *                          array('boolean', 'int'),
240
 *                          array('boolean', 'int', 'boolean'),
241
 *                          array('boolean', 'string'),
242
 *                          array('boolean', 'string', 'boolean'),
243
 *                      ),
244
 *                 'docstring' => 'Is the value an 8?'
245
 *             ),
246
 *     ),
247
 *     1,
248
 *     0
249
 * ); 
250
 * </code>
251
 *
252
 * @category   Web Services
253
 * @package    XML_RPC
254
 * @author     Edd Dumbill <edd@usefulinc.com>
255
 * @author     Stig Bakken <stig@php.net>
256
 * @author     Martin Jansen <mj@php.net>
257
 * @author     Daniel Convissor <danielc@php.net>
258
 * @copyright  1999-2001 Edd Dumbill, 2001-2010 The PHP Group
259
 * @license    http://www.php.net/license/3_01.txt  PHP License
260
 * @version    Release: @package_version@
261
 * @link       http://pear.php.net/package/XML_RPC
262
 */
263
class XML_RPC_Server
264
{
265
    /**
266
     * Should the payload's content be passed through mb_convert_encoding()?
267
     *
268
     * @see XML_RPC_Server::setConvertPayloadEncoding()
269
     * @since Property available since Release 1.5.1
270
     * @var boolean
271
     */
272
    var $convert_payload_encoding = false;
273

    
274
    /**
275
     * The dispatch map, listing the methods this server provides.
276
     * @var array
277
     */
278
    var $dmap = array();
279

    
280
    /**
281
     * The present response's encoding
282
     * @var string
283
     * @see XML_RPC_Message::getEncoding()
284
     */
285
    var $encoding = '';
286

    
287
    /**
288
     * Debug mode (0 = off, 1 = on)
289
     * @var integer
290
     */
291
    var $debug = 0;
292

    
293
    /**
294
     * The response's HTTP headers
295
     * @var string
296
     */
297
    var $server_headers = '';
298

    
299
    /**
300
     * The response's XML payload
301
     * @var string
302
     */
303
    var $server_payload = '';
304

    
305

    
306
    /**
307
     * The HTTP request data
308
     * @null
309
     */
310
    var $client_data = '';
311

    
312
    /**
313
     * Constructor for the XML_RPC_Server class
314
     *
315
     * @param array $dispMap   the dispatch map. An associative array
316
     *                          explaining each function. The keys of the main
317
     *                          array are the procedure names used by the
318
     *                          clients. The value is another associative array
319
     *                          that contains up to three elements:
320
     *                            + The 'function' element's value is the name
321
     *                              of the function or method that gets called.
322
     *                              To define a class' method: 'class::method'.
323
     *                            + The 'signature' element (optional) is an
324
     *                              array describing the return values and
325
     *                              parameters
326
     *                            + The 'docstring' element (optional) is a
327
     *                              string describing what the method does
328
     * @param int $serviceNow  should the HTTP response be sent now?
329
     *                          (1 = yes, 0 = no)
330
     * @param int $debug       should debug output be displayed?
331
     *                          (1 = yes, 0 = no)
332
     *
333
     * @return void
334
     */
335
    function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0)
336
    {
337

    
338
        if ($debug) {
339
            $this->debug = 1;
340
        } else {
341
            $this->debug = 0;
342
        }
343

    
344
        $this->dmap = $dispMap;
345

    
346
        if ($serviceNow) {
347
            $this->service();
348
        } else {
349
            $this->createServerPayload();
350
            $this->createServerHeaders();
351
        }
352
    }
353

    
354
    /**
355
     * @return string  the debug information if debug debug mode is on
356
     */
357
    function serializeDebug()
358
    {
359
        global $XML_RPC_Server_debuginfo;
360

    
361
        if ($this->debug) {
362
            XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n"
363
                                    . $this->server_payload . $this->client_data
364
                                    . "\n" . '^^^ END POST DATA ^^^');
365
        }
366

    
367
        if ($XML_RPC_Server_debuginfo != '') {
368
            return "<!-- PEAR XML_RPC SERVER DEBUG INFO:\n\n"
369
                   . str_replace('--', '- - ', $XML_RPC_Server_debuginfo)
370
                   . "-->\n";
371
        } else {
372
            return '';
373
        }
374
    }
375

    
376
    /**
377
     * Sets whether the payload's content gets passed through
378
     * mb_convert_encoding()
379
     *
380
     * Returns PEAR_ERROR object if mb_convert_encoding() isn't available.
381
     *
382
     * @param int $in  where 1 = on, 0 = off
383
     *
384
     * @return void
385
     *
386
     * @see XML_RPC_Message::getEncoding()
387
     * @since Method available since Release 1.5.1
388
     */
389
    function setConvertPayloadEncoding($in)
390
    {
391
        if ($in && !function_exists('mb_convert_encoding')) {
392
            return $this->raiseError('mb_convert_encoding() is not available',
393
                              XML_RPC_ERROR_PROGRAMMING);
394
        }
395
        $this->convert_payload_encoding = $in;
396
    }
397

    
398
    /**
399
     * Sends the response
400
     *
401
     * The encoding and content-type are determined by
402
     * XML_RPC_Message::getEncoding()
403
     *
404
     * @return void
405
     *
406
     * @uses XML_RPC_Server::createServerPayload(),
407
     *       XML_RPC_Server::createServerHeaders()
408
     */
409
    function service()
410
    {
411
        if (!$this->server_payload) {
412
            $this->createServerPayload();
413
        }
414
        if (!$this->server_headers) {
415
            $this->createServerHeaders();
416
        }
417

    
418
        /*
419
         * $server_headers needs to remain a string for compatibility with
420
         * old scripts using this package, but PHP 4.4.2 no longer allows
421
         * line breaks in header() calls.  So, we split each header into
422
         * an individual call.  The initial replace handles the off chance
423
         * that someone composed a single header with multiple lines, which
424
         * the RFCs allow.
425
         */
426
        $this->server_headers = preg_replace("@[\r\n]+[ \t]+@",
427
                                ' ', trim($this->server_headers));
428
        $headers = preg_split("@[\r\n]+@", $this->server_headers);
429
        foreach ($headers as $header)
430
        {
431
            header($header);
432
        }
433

    
434
        print $this->server_payload;
435
    }
436

    
437
    /**
438
     * Generates the payload and puts it in the $server_payload property
439
     *
440
     * If XML_RPC_Server::setConvertPayloadEncoding() was set to true,
441
     * the payload gets passed through mb_convert_encoding()
442
     * to ensure the payload matches the encoding set in the
443
     * XML declaration.  The encoding type can be manually set via
444
     * XML_RPC_Message::setSendEncoding().
445
     *
446
     * @return void
447
     *
448
     * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding,
449
     *       XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug()
450
     * @see  XML_RPC_Server::setConvertPayloadEncoding()
451
     */
452
    function createServerPayload()
453
    {
454
	$this->client_data = file_get_contents("php://input");
455

    
456
        $r = $this->parseRequest($this->client_data);
457
        $this->server_payload = '<?xml version="1.0" encoding="'
458
                              . $this->encoding . '"?>' . "\n"
459
                              . $this->serializeDebug()
460
                              . $r->serialize();
461
        if ($this->convert_payload_encoding) {
462
            $this->server_payload = mb_convert_encoding($this->server_payload,
463
                                                        $this->encoding);
464
        }
465
    }
466

    
467
    /**
468
     * Determines the HTTP headers and puts them in the $server_headers
469
     * property
470
     *
471
     * @return boolean  TRUE if okay, FALSE if $server_payload isn't set.
472
     *
473
     * @uses XML_RPC_Server::createServerPayload(),
474
     *       XML_RPC_Server::$server_headers
475
     */
476
    function createServerHeaders()
477
    {
478
        if (!$this->server_payload) {
479
            return false;
480
        }
481
        $this->server_headers = 'Content-Length: '
482
                              . strlen($this->server_payload) . "\r\n"
483
                              . 'Content-Type: text/xml;'
484
                              . ' charset=' . $this->encoding;
485
        return true;
486
    }
487

    
488
    /**
489
     * @return array
490
     */
491
    function verifySignature($in, $sig)
492
    {
493
        for ($i = 0; $i < sizeof($sig); $i++) {
494
            // check each possible signature in turn
495
            $cursig = $sig[$i];
496
            if (sizeof($cursig) == $in->getNumParams() + 1) {
497
                $itsOK = 1;
498
                for ($n = 0; $n < $in->getNumParams(); $n++) {
499
                    $p = $in->getParam($n);
500
                    // print "<!-- $p -->\n";
501
                    if ($p->kindOf() == 'scalar') {
502
                        $pt = $p->scalartyp();
503
                    } else {
504
                        $pt = $p->kindOf();
505
                    }
506
                    // $n+1 as first type of sig is return type
507
                    if ($pt != $cursig[$n+1]) {
508
                        $itsOK = 0;
509
                        $pno = $n+1;
510
                        $wanted = $cursig[$n+1];
511
                        $got = $pt;
512
                        break;
513
                    }
514
                }
515
                if ($itsOK) {
516
                    return array(1);
517
                }
518
            }
519
        }
520
        if (isset($wanted)) {
521
            return array(0, "Wanted ${wanted}, got ${got} at param ${pno}");
522
        } else {
523
            $allowed = array();
524
            foreach ($sig as $val) {
525
                end($val);
526
                $allowed[] = key($val);
527
            }
528
            $allowed = array_unique($allowed);
529
            $last = count($allowed) - 1;
530
            if ($last > 0) {
531
                $allowed[$last] = 'or ' . $allowed[$last];
532
            }
533
            return array(0,
534
                         'Signature permits ' . implode(', ', $allowed)
535
                                . ' parameters but the request had '
536
                                . $in->getNumParams());
537
        }
538
    }
539

    
540
    /**
541
     * @return object  a new XML_RPC_Response object
542
     *
543
     * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding
544
     */
545
    function parseRequest($data = '')
546
    {
547
        global $XML_RPC_xh,
548
                $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml,
549
                $XML_RPC_defencoding, $XML_RPC_Server_dmap;
550

    
551
        if ($data == '') {
552
            $data = file_get_contents("php://input");
553
	    $this->client_data = $data;
554
        }
555

    
556
        $this->encoding = XML_RPC_Message::getEncoding($data);
557
        $parser_resource = xml_parser_create($this->encoding);
558
        $parser = (int) $parser_resource;
559

    
560
        $XML_RPC_xh[$parser] = array();
561
        $XML_RPC_xh[$parser]['cm']     = 0;
562
        $XML_RPC_xh[$parser]['isf']    = 0;
563
        $XML_RPC_xh[$parser]['params'] = array();
564
        $XML_RPC_xh[$parser]['method'] = '';
565
        $XML_RPC_xh[$parser]['stack'] = array();	
566
        $XML_RPC_xh[$parser]['valuestack'] = array();	
567

    
568
        $plist = '';
569

    
570
        // decompose incoming XML into request structure
571

    
572
        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
573
        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
574
        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
575
        if (!xml_parse($parser_resource, $data, 1)) {
576
            // return XML error as a faultCode
577
            $r = new XML_RPC_Response(0,
578
                                      $XML_RPC_errxml+xml_get_error_code($parser_resource),
579
                                      sprintf('XML error: %s at line %d',
580
                                              xml_error_string(xml_get_error_code($parser_resource)),
581
                                              xml_get_current_line_number($parser_resource)));
582
            xml_parser_free($parser_resource);
583
        } elseif ($XML_RPC_xh[$parser]['isf']>1) {
584
            $r = new XML_RPC_Response(0,
585
                                      $XML_RPC_err['invalid_request'],
586
                                      $XML_RPC_str['invalid_request']
587
                                      . ': '
588
                                      . $XML_RPC_xh[$parser]['isf_reason']);
589
            xml_parser_free($parser_resource);
590
        } else {
591
            xml_parser_free($parser_resource);
592
            $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']);
593
            // now add parameters in
594
            for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) {
595
                // print '<!-- ' . $XML_RPC_xh[$parser]['params'][$i]. "-->\n";
596
                $plist .= "$i - " . var_export($XML_RPC_xh[$parser]['params'][$i], true) . " \n";
597
                $m->addParam($XML_RPC_xh[$parser]['params'][$i]);
598
            }
599

    
600
            if ($this->debug) {
601
                XML_RPC_Server_debugmsg($plist);
602
            }
603

    
604
            // now to deal with the method
605
            $methName = $XML_RPC_xh[$parser]['method'];
606
            if (strpos($methName, 'system.') === 0) {
607
                $dmap = $XML_RPC_Server_dmap;
608
                $sysCall = 1;
609
            } else {
610
                $dmap = $this->dmap;
611
                $sysCall = 0;
612
            }
613

    
614
            if (isset($dmap[$methName]['function'])
615
                && is_string($dmap[$methName]['function'])
616
                && strpos($dmap[$methName]['function'], '::') !== false)
617
            {
618
                $dmap[$methName]['function'] =
619
                        explode('::', $dmap[$methName]['function']);
620
            }
621

    
622
            if (isset($dmap[$methName]['function'])
623
                && is_callable($dmap[$methName]['function']))
624
            {
625
                // dispatch if exists
626
                if (isset($dmap[$methName]['signature'])) {
627
                    $sr = $this->verifySignature($m,
628
                                                 $dmap[$methName]['signature'] );
629
                }
630
                if (!isset($dmap[$methName]['signature']) || $sr[0]) {
631
                    // if no signature or correct signature
632
                    if ($sysCall) {
633
                        $r = call_user_func($dmap[$methName]['function'], $this, $m);
634
                    } else {
635
                        $r = call_user_func($dmap[$methName]['function'], $m);
636
                    }
637
                    if (!is_a($r, 'XML_RPC_Response')) {
638
                        $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'],
639
                                                  $XML_RPC_str['not_response_object']);
640
                    }
641
                } else {
642
                    $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
643
                                              $XML_RPC_str['incorrect_params']
644
                                              . ': ' . $sr[1]);
645
                }
646
            } else {
647
                // else prepare error response
648
                $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'],
649
                                          $XML_RPC_str['unknown_method']);
650
            }
651
        }
652
        return $r;
653
    }
654

    
655
    /**
656
     * Echos back the input packet as a string value
657
     *
658
     * @return void
659
     *
660
     * Useful for debugging.
661
     */
662
    function echoInput()
663
    {
664
        $r = new XML_RPC_Response(0);
665
        $r->xv = new XML_RPC_Value("'Aha said I: '" . $this->client_data, 'string');
666
        print $r->serialize();
667
    }
668
}
669

    
670
/*
671
 * Local variables:
672
 * tab-width: 4
673
 * c-basic-offset: 4
674
 * c-hanging-comment-ender-p: nil
675
 * End:
676
 */
677

    
678
?>
(67-67/68)