Dotclear

source: inc/public/lib.urlhandlers.php @ 3526:4659a409fa68

Revision 3526:4659a409fa68, 18.6 KB checked in by franck <carnet.franck.paul@…>, 9 years ago (diff)

Allow 3rd party additional headers and extend arg of urlHandlerServeDocument in order to cope with

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
7# Licensed under the GPL version 2.0 license.
8# See LICENSE file or
9# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10#
11# -- END LICENSE BLOCK -----------------------------------------
12if (!defined('DC_RC_PATH')) { return; }
13
14class dcUrlHandlers extends urlHandler
15{
16     public $args;
17
18     public function getURLFor($type,$value='') {
19          $core =& $GLOBALS['core'];
20          $url = $core->callBehavior("publicGetURLFor",$type,$value);
21          if (!$url) {
22               $url = $this->getBase($type);
23               if ($value) {
24                    if ($url) {
25                         $url .= '/';
26                    }
27                    $url .= $value;
28               }
29          }
30          return $url;
31     }
32
33     public function register($type,$url,$representation,$handler)
34     {
35          $core =& $GLOBALS['core'];
36          $t = new ArrayObject(array($type,$url,$representation,$handler));
37          $core->callBehavior("publicRegisterURL",$t);
38          parent::register($t[0],$t[1],$t[2],$t[3]);
39     }
40
41     public static function p404()
42     {
43          throw new Exception ("Page not found",404);
44     }
45
46     public static function default404($args,$type,$e)
47     {
48          if ($e->getCode() != 404) {
49               throw $e;
50          }
51          $_ctx =& $GLOBALS['_ctx'];
52          $core = $GLOBALS['core'];
53
54          header('Content-Type: text/html; charset=UTF-8');
55          http::head(404,'Not Found');
56          $core->url->type = '404';
57          $_ctx->current_tpl = '404.html';
58          $_ctx->content_type = 'text/html';
59
60          echo $core->tpl->getData($_ctx->current_tpl);
61
62          # --BEHAVIOR-- publicAfterDocument
63          $core->callBehavior('publicAfterDocument',$core);
64          exit;
65     }
66
67     protected static function getPageNumber(&$args)
68     {
69          if (preg_match('#(^|/)page/([0-9]+)$#',$args,$m)) {
70               $n = (integer) $m[2];
71               if ($n > 0) {
72                    $args = preg_replace('#(^|/)page/([0-9]+)$#','',$args);
73                    return $n;
74               }
75          }
76
77          return false;
78     }
79
80     protected static function serveDocument($tpl,$content_type='text/html',$http_cache=true,$http_etag=true)
81     {
82          $_ctx =& $GLOBALS['_ctx'];
83          $core =& $GLOBALS['core'];
84
85          if ($_ctx->nb_entry_per_page === null) {
86               $_ctx->nb_entry_per_page = $core->blog->settings->system->nb_post_per_page;
87          }
88          if ($_ctx->nb_entry_first_page === null) {
89               $_ctx->nb_entry_first_page = $_ctx->nb_entry_per_page;
90          }
91
92          $tpl_file = $core->tpl->getFilePath($tpl);
93
94          if (!$tpl_file) {
95               throw new Exception('Unable to find template ');
96          }
97
98          $result = new ArrayObject;
99
100          $_ctx->current_tpl = $tpl;
101          $_ctx->content_type = $content_type;
102          $_ctx->http_cache = $http_cache;
103          $_ctx->http_etag = $http_etag;
104          $core->callBehavior('urlHandlerBeforeGetData',$_ctx);
105
106          if ($_ctx->http_cache) {
107               $GLOBALS['mod_files'][] = $tpl_file;
108               http::cache($GLOBALS['mod_files'],$GLOBALS['mod_ts']);
109          }
110
111          header('Content-Type: '.$_ctx->content_type.'; charset=UTF-8');
112
113          // Additional headers
114          $headers = new ArrayObject;
115          if ($core->blog->settings->system->prevents_clickjacking) {
116               if ($_ctx->exists('xframeoption')) {
117                    $url = parse_url($_ctx->xframeoption);
118                    $header = sprintf('X-Frame-Options: %s',
119                         is_array($url)?("ALLOW-FROM ".$url['scheme'].'://'.$url['host']):'SAMEORIGIN');
120               } else {
121                    // Prevents Clickjacking as far as possible
122                    $header = 'X-Frame-Options: SAMEORIGIN'; // FF 3.6.9+ Chrome 4.1+ IE 8+ Safari 4+ Opera 10.5+
123               }
124               $headers[] = $header;
125          }
126          # --BEHAVIOR-- urlHandlerServeDocumentHeaders
127          $core->callBehavior('urlHandlerServeDocumentHeaders',$headers);
128
129          // Send additional headers if any
130          foreach ($headers as $header) {
131               header($header);
132          }
133
134          $result['content'] = $core->tpl->getData($_ctx->current_tpl);
135          $result['content_type'] = $_ctx->content_type;
136          $result['tpl'] = $_ctx->current_tpl;
137          $result['blogupddt'] = $core->blog->upddt;
138          $result['headers'] = $headers;
139
140          # --BEHAVIOR-- urlHandlerServeDocument
141          $core->callBehavior('urlHandlerServeDocument',$result);
142
143          if ($_ctx->http_cache && $_ctx->http_etag) {
144               http::etag($result['content'],http::getSelfURI());
145          }
146          echo $result['content'];
147     }
148
149     public function getDocument()
150     {
151          $core =& $GLOBALS['core'];
152
153          $type = $args = '';
154
155          if ($this->mode == 'path_info')
156          {
157               $part = substr($_SERVER['PATH_INFO'],1);
158          }
159          else
160          {
161               $part = '';
162
163               $qs = $this->parseQueryString();
164
165               # Recreates some _GET and _REQUEST pairs
166               if (!empty($qs))
167               {
168                    foreach ($_GET as $k => $v) {
169                         if (isset($_REQUEST[$k])) {
170                              unset($_REQUEST[$k]);
171                         }
172                    }
173                    $_GET = $qs;
174                    $_REQUEST = array_merge($qs,$_REQUEST);
175
176                    list($k,$v) = each($qs);
177                    if ($v === null) {
178                         $part = $k;
179                         unset($_GET[$k]);
180                         unset($_REQUEST[$k]);
181                    }
182               }
183          }
184
185          $_SERVER['URL_REQUEST_PART'] = $part;
186
187          $this->getArgs($part,$type,$this->args);
188
189          # --BEHAVIOR-- urlHandlerGetArgsDocument
190          $core->callBehavior('urlHandlerGetArgsDocument',$this);
191
192          if (!$type)
193          {
194               $this->type = 'default';
195               $this->callDefaultHandler($this->args);
196          }
197          else
198          {
199               $this->type = $type;
200               $this->callHandler($type,$this->args);
201          }
202     }
203
204     public static function home($args)
205     {
206          $n = self::getPageNumber($args);
207
208          if ($args && !$n)
209          {
210               # "Then specified URL went unrecognized by all URL handlers and
211               # defaults to the home page, but is not a page number.
212               self::p404();
213          }
214          else
215          {
216               $_ctx =& $GLOBALS['_ctx'];
217               $core =& $GLOBALS['core'];
218
219               if ($n) {
220                    $GLOBALS['_page_number'] = $n;
221                    $core->url->type = $n > 1 ? 'default-page' : 'default';
222               }
223
224               if (empty($_GET['q'])) {
225                    if ($core->blog->settings->system->nb_post_for_home !== null) {
226                         $_ctx->nb_entry_first_page = $core->blog->settings->system->nb_post_for_home;
227                    }
228                    self::serveDocument('home.html');
229                    $core->blog->publishScheduledEntries();
230               } else {
231                    self::search();
232               }
233          }
234     }
235
236     public static function search()
237     {
238          $_ctx =& $GLOBALS['_ctx'];
239          $core =& $GLOBALS['core'];
240
241          if ($core->blog->settings->system->no_search) {
242
243               # Search is disabled for this blog.
244               self::p404();
245
246          } else {
247
248               $core->url->type='search';
249
250               $GLOBALS['_search'] = !empty($_GET['q']) ? rawurldecode($_GET['q']) : '';
251               if ($GLOBALS['_search']) {
252                    $params = new ArrayObject(array('search' => $GLOBALS['_search']));
253                    $core->callBehavior('publicBeforeSearchCount',$params);
254                    $GLOBALS['_search_count'] = $core->blog->getPosts($params,true)->f(0);
255               }
256
257               self::serveDocument('search.html');
258          }
259     }
260
261     public static function lang($args)
262     {
263          $_ctx =& $GLOBALS['_ctx'];
264          $core =& $GLOBALS['core'];
265
266          $n = self::getPageNumber($args);
267          $params = new ArrayObject(array(
268               'lang' => $args));
269
270          $core->callBehavior('publicLangBeforeGetLangs',$params,$args);
271
272          $_ctx->langs = $core->blog->getLangs($params);
273
274          if ($_ctx->langs->isEmpty()) {
275               # The specified language does not exist.
276               self::p404();
277          }
278          else
279          {
280               if ($n) {
281                    $GLOBALS['_page_number'] = $n;
282               }
283               $_ctx->cur_lang = $args;
284               self::home(null);
285          }
286     }
287
288     public static function category($args)
289     {
290          $_ctx =& $GLOBALS['_ctx'];
291          $core =& $GLOBALS['core'];
292
293          $n = self::getPageNumber($args);
294
295          if ($args == '' && !$n) {
296               # No category was specified.
297               self::p404();
298          }
299          else
300          {
301               $params = new ArrayObject(array(
302                    'cat_url' => $args,
303                    'post_type' => 'post',
304                    'without_empty' => false));
305
306               $core->callBehavior('publicCategoryBeforeGetCategories',$params,$args);
307
308               $_ctx->categories = $core->blog->getCategories($params);
309
310               if ($_ctx->categories->isEmpty()) {
311                    # The specified category does no exist.
312                    self::p404();
313               }
314               else
315               {
316                    if ($n) {
317                         $GLOBALS['_page_number'] = $n;
318                    }
319                    self::serveDocument('category.html');
320               }
321          }
322     }
323
324     public static function archive($args)
325     {
326          $_ctx =& $GLOBALS['_ctx'];
327          $core =& $GLOBALS['core'];
328
329          $year = $month = $cat_url = null;
330          # Nothing or year and month
331          if ($args == '')
332          {
333               self::serveDocument('archive.html');
334          }
335          elseif (preg_match('|^/([0-9]{4})/([0-9]{2})$|',$args,$m))
336          {
337               $params = new ArrayObject(array(
338                    'year' => $m[1],
339                    'month' => $m[2],
340                    'type' => 'month'));
341
342               $core->callBehavior('publicArchiveBeforeGetDates',$params,$args);
343
344               $_ctx->archives = $core->blog->getDates($params);
345
346               if ($_ctx->archives->isEmpty()) {
347                    # There is no entries for the specified period.
348                    self::p404();
349               }
350               else
351               {
352                    self::serveDocument('archive_month.html');
353               }
354          }
355          else {
356               # The specified URL is not a date.
357               self::p404();
358          }
359     }
360
361     public static function post($args)
362     {
363          if ($args == '') {
364               # No entry was specified.
365               self::p404();
366          }
367          else
368          {
369               $_ctx =& $GLOBALS['_ctx'];
370               $core =& $GLOBALS['core'];
371
372               $core->blog->withoutPassword(false);
373
374               $params = new ArrayObject(array(
375                    'post_url' => $args));
376
377               $core->callBehavior('publicPostBeforeGetPosts',$params,$args);
378
379               $_ctx->posts = $core->blog->getPosts($params);
380
381               $_ctx->comment_preview = new ArrayObject();
382               $_ctx->comment_preview['content'] = '';
383               $_ctx->comment_preview['rawcontent'] = '';
384               $_ctx->comment_preview['name'] = '';
385               $_ctx->comment_preview['mail'] = '';
386               $_ctx->comment_preview['site'] = '';
387               $_ctx->comment_preview['preview'] = false;
388               $_ctx->comment_preview['remember'] = false;
389
390               $core->blog->withoutPassword(true);
391
392               if ($_ctx->posts->isEmpty())
393               {
394                    # The specified entry does not exist.
395                    self::p404();
396               }
397               else
398               {
399                    $post_id = $_ctx->posts->post_id;
400                    $post_password = $_ctx->posts->post_password;
401
402                    # Password protected entry
403                    if ($post_password != '' && !$_ctx->preview)
404                    {
405                         # Get passwords cookie
406                         if (isset($_COOKIE['dc_passwd'])) {
407                              $pwd_cookie = json_decode($_COOKIE['dc_passwd']);
408                              if ($pwd_cookie === NULL) {
409                                   $pwd_cookie = array();
410                              } else {
411                                   $pwd_cookie = (array) $pwd_cookie;
412                              }
413                         } else {
414                              $pwd_cookie = array();
415                         }
416
417                         # Check for match
418                         # Note: We must prefix post_id key with '#'' in pwd_cookie array in order to avoid integer conversion
419                         # because MyArray["12345"] is treated as MyArray[12345]
420                         if ((!empty($_POST['password']) && $_POST['password'] == $post_password)
421                         || (isset($pwd_cookie['#'.$post_id]) && $pwd_cookie['#'.$post_id] == $post_password))
422                         {
423                              $pwd_cookie['#'.$post_id] = $post_password;
424                              setcookie('dc_passwd',json_encode($pwd_cookie),0,'/');
425                         }
426                         else
427                         {
428                              self::serveDocument('password-form.html','text/html',false);
429                              return;
430                         }
431                    }
432
433                    $post_comment =
434                         isset($_POST['c_name']) && isset($_POST['c_mail']) &&
435                         isset($_POST['c_site']) && isset($_POST['c_content']) &&
436                         $_ctx->posts->commentsActive();
437
438                    # Posting a comment
439                    if ($post_comment)
440                    {
441                         # Spam trap
442                         if (!empty($_POST['f_mail'])) {
443                              http::head(412,'Precondition Failed');
444                              header('Content-Type: text/plain');
445                              echo "So Long, and Thanks For All the Fish";
446                              # Exits immediately the application to preserve the server.
447                              exit;
448                         }
449
450                         $name = $_POST['c_name'];
451                         $mail = $_POST['c_mail'];
452                         $site = $_POST['c_site'];
453                         $content = $_POST['c_content'];
454                         $preview = !empty($_POST['preview']);
455
456                         if ($content != '')
457                         {
458                              # --BEHAVIOR-- publicBeforeCommentTransform
459                              $buffer = $core->callBehavior('publicBeforeCommentTransform',$content);
460                              if ($buffer != '') {
461                                   $content = $buffer;
462                              } else {
463                                   if ($core->blog->settings->system->wiki_comments) {
464                                        $core->initWikiComment();
465                                   } else {
466                                        $core->initWikiSimpleComment();
467                                   }
468                                   $content = $core->wikiTransform($content);
469                              }
470                              $content = $core->HTMLfilter($content);
471                         }
472
473                         $_ctx->comment_preview['content'] = $content;
474                         $_ctx->comment_preview['rawcontent'] = $_POST['c_content'];
475                         $_ctx->comment_preview['name'] = $name;
476                         $_ctx->comment_preview['mail'] = $mail;
477                         $_ctx->comment_preview['site'] = $site;
478
479                         if ($preview)
480                         {
481                              # --BEHAVIOR-- publicBeforeCommentPreview
482                              $core->callBehavior('publicBeforeCommentPreview',$_ctx->comment_preview);
483
484                              $_ctx->comment_preview['preview'] = true;
485                         }
486                         else
487                         {
488                              # Post the comment
489                              $cur = $core->con->openCursor($core->prefix.'comment');
490                              $cur->comment_author = $name;
491                              $cur->comment_site = html::clean($site);
492                              $cur->comment_email = html::clean($mail);
493                              $cur->comment_content = $content;
494                              $cur->post_id = $_ctx->posts->post_id;
495                              $cur->comment_status = $core->blog->settings->system->comments_pub ? 1 : -1;
496                              $cur->comment_ip = http::realIP();
497
498                              $redir = $_ctx->posts->getURL();
499                              $redir .= $core->blog->settings->system->url_scan == 'query_string' ? '&' : '?';
500
501                              try
502                              {
503                                   if (!text::isEmail($cur->comment_email)) {
504                                        throw new Exception(__('You must provide a valid email address.'));
505                                   }
506
507                                   # --BEHAVIOR-- publicBeforeCommentCreate
508                                   $core->callBehavior('publicBeforeCommentCreate',$cur);
509                                   if ($cur->post_id) {
510                                        $comment_id = $core->blog->addComment($cur);
511
512                                        # --BEHAVIOR-- publicAfterCommentCreate
513                                        $core->callBehavior('publicAfterCommentCreate',$cur,$comment_id);
514                                   }
515
516                                   if ($cur->comment_status == 1) {
517                                        $redir_arg = 'pub=1';
518                                   } else {
519                                        $redir_arg = 'pub=0';
520                                   }
521
522                                   header('Location: '.$redir.$redir_arg);
523                              }
524                              catch (Exception $e)
525                              {
526                                   $_ctx->form_error = $e->getMessage();
527                                   $_ctx->form_error;
528                              }
529                         }
530                    }
531
532                    # The entry
533                    if ($_ctx->posts->trackbacksActive()) {
534                         header('X-Pingback: '.$core->blog->url.$core->url->getURLFor("xmlrpc",$core->blog->id));
535                         header('Link: <'.$core->blog->url.$core->url->getURLFor('webmention').'>; rel="webmention"');
536                    }
537                    self::serveDocument('post.html');
538               }
539          }
540     }
541
542     public static function preview($args)
543     {
544          $core = $GLOBALS['core'];
545          $_ctx = $GLOBALS['_ctx'];
546
547          if (!preg_match('#^(.+?)/([0-9a-z]{40})/(.+?)$#',$args,$m)) {
548               # The specified Preview URL is malformed.
549               self::p404();
550          }
551          else
552          {
553               $user_id = $m[1];
554               $user_key = $m[2];
555               $post_url = $m[3];
556               if (!$core->auth->checkUser($user_id,null,$user_key)) {
557                    # The user has no access to the entry.
558                    self::p404();
559               }
560               else
561               {
562                    $_ctx->preview = true;
563                    if (defined ("DC_ADMIN_URL")) {
564                         $_ctx->xframeoption=DC_ADMIN_URL;
565                    }
566                    self::post($post_url);
567               }
568          }
569     }
570
571     public static function feed($args)
572     {
573          $type = null;
574          $comments = false;
575          $cat_url = false;
576          $post_id = null;
577          $subtitle = '';
578
579          $mime = 'application/xml';
580
581          $_ctx =& $GLOBALS['_ctx'];
582          $core =& $GLOBALS['core'];
583
584          if (preg_match('!^([a-z]{2}(-[a-z]{2})?)/(.*)$!',$args,$m)) {
585               $params = new ArrayObject(array('lang' => $m[1]));
586
587               $args = $m[3];
588
589               $core->callBehavior('publicFeedBeforeGetLangs',$params,$args);
590
591               $_ctx->langs = $core->blog->getLangs($params);
592
593               if ($_ctx->langs->isEmpty()) {
594                    # The specified language does not exist.
595                    self::p404();
596                    return;
597               } else {
598                    $_ctx->cur_lang = $m[1];
599               }
600          }
601
602          if (preg_match('#^rss2/xslt$#',$args,$m))
603          {
604               # RSS XSLT stylesheet
605               self::serveDocument('rss2.xsl','text/xml');
606               return;
607          }
608          elseif (preg_match('#^(atom|rss2)/comments/([0-9]+)$#',$args,$m))
609          {
610               # Post comments feed
611               $type = $m[1];
612               $comments = true;
613               $post_id = (integer) $m[2];
614          }
615          elseif (preg_match('#^(?:category/(.+)/)?(atom|rss2)(/comments)?$#',$args,$m))
616          {
617               # All posts or comments feed
618               $type = $m[2];
619               $comments = !empty($m[3]);
620               if (!empty($m[1])) {
621                    $cat_url = $m[1];
622               }
623          }
624          else
625          {
626               # The specified Feed URL is malformed.
627               self::p404();
628               return;
629          }
630
631          if ($cat_url)
632          {
633               $params = new ArrayObject(array(
634                    'cat_url' => $cat_url,
635                    'post_type' => 'post'));
636
637               $core->callBehavior('publicFeedBeforeGetCategories',$params,$args);
638
639               $_ctx->categories = $core->blog->getCategories($params);
640
641               if ($_ctx->categories->isEmpty()) {
642                    # The specified category does no exist.
643                    self::p404();
644                    return;
645               }
646
647               $subtitle = ' - '.$_ctx->categories->cat_title;
648          }
649          elseif ($post_id)
650          {
651               $params = new ArrayObject(array(
652                    'post_id' => $post_id,
653                    'post_type' => ''));
654
655               $core->callBehavior('publicFeedBeforeGetPosts',$params,$args);
656
657               $_ctx->posts = $core->blog->getPosts($params);
658
659               if ($_ctx->posts->isEmpty()) {
660                    # The specified post does not exist.
661                    self::p404();
662                    return;
663               }
664
665               $subtitle = ' - '.$_ctx->posts->post_title;
666          }
667
668          $tpl = $type;
669          if ($comments) {
670               $tpl .= '-comments';
671               $_ctx->nb_comment_per_page = $core->blog->settings->system->nb_comment_per_feed;
672          } else {
673               $_ctx->nb_entry_per_page = $core->blog->settings->system->nb_post_per_feed;
674               $_ctx->short_feed_items = $core->blog->settings->system->short_feed_items;
675          }
676          $tpl .= '.xml';
677
678          if ($type == 'atom') {
679               $mime = 'application/atom+xml';
680          }
681
682          $_ctx->feed_subtitle = $subtitle;
683
684          header('X-Robots-Tag: '.context::robotsPolicy($core->blog->settings->system->robots_policy,''));
685          self::serveDocument($tpl,$mime);
686          if (!$comments && !$cat_url) {
687               $core->blog->publishScheduledEntries();
688          }
689     }
690
691     public static function trackback($args)
692     {
693          if (!preg_match('/^[0-9]+$/',$args)) {
694               # The specified trackback URL is not an number
695               self::p404();
696          } else {
697               $core =& $GLOBALS['core'];
698
699               // Save locally post_id from args
700               $post_id = (integer) $args;
701
702               if (!is_array($args)) $args = array();
703               $args['post_id'] = $post_id;
704               $args['type'] = 'trackback';
705
706               # --BEHAVIOR-- publicBeforeReceiveTrackback
707               $core->callBehavior('publicBeforeReceiveTrackback',$core,$args);
708
709               $tb = new dcTrackback($core);
710               $tb->receiveTrackback($post_id);
711          }
712     }
713
714     public static function webmention($args)
715     {
716          $core =& $GLOBALS['core'];
717          if (!is_array($args)) $args = array();
718          $args['type'] = 'webmention';
719
720          # --BEHAVIOR-- publicBeforeReceiveTrackback
721          $core->callBehavior('publicBeforeReceiveTrackback',$core,$args);
722
723          $tb = new dcTrackback($core);
724          $tb->receiveWebmention();
725     }
726
727     public static function rsd($args)
728     {
729          $core =& $GLOBALS['core'];
730          http::cache($GLOBALS['mod_files'],$GLOBALS['mod_ts']);
731
732          header('Content-Type: text/xml; charset=UTF-8');
733          echo
734          '<?xml version="1.0" encoding="UTF-8"?>'."\n".
735          '<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">'."\n".
736          "<service>\n".
737          "  <engineName>Dotclear</engineName>\n".
738          "  <engineLink>http://www.dotclear.org/</engineLink>\n".
739          '  <homePageLink>'.html::escapeHTML($core->blog->url)."</homePageLink>\n";
740
741          if ($core->blog->settings->system->enable_xmlrpc)
742          {
743               $u = sprintf(DC_XMLRPC_URL,$core->blog->url,$core->blog->id);
744
745               echo
746               "  <apis>\n".
747               '    <api name="WordPress" blogID="1" preferred="true" apiLink="'.$u.'"/>'."\n".
748               '    <api name="Movable Type" blogID="1" preferred="false" apiLink="'.$u.'"/>'."\n".
749               '    <api name="MetaWeblog" blogID="1" preferred="false" apiLink="'.$u.'"/>'."\n".
750               '    <api name="Blogger" blogID="1" preferred="false" apiLink="'.$u.'"/>'."\n".
751               "  </apis>\n";
752          }
753
754          echo
755          "</service>\n".
756          "</rsd>\n";
757     }
758
759     public static function xmlrpc($args)
760     {
761          $core =& $GLOBALS['core'];
762          $blog_id = preg_replace('#^([^/]*).*#','$1',$args);
763          $server = new dcXmlRpc($core,$blog_id);
764          $server->serve();
765     }
766}
Note: See TracBrowser for help on using the repository browser.

Sites map