home *** CD-ROM | disk | FTP | other *** search
/ Clickx 23 / Clickx 23.iso / DATA / wordpress / xmlrpc.php < prev   
Encoding:
PHP Script  |  2005-08-14  |  37.4 KB  |  1,337 lines

  1. <?php
  2.  
  3. # fix for mozBlog and other cases where '<?xml' isn't on the very first line
  4. $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);
  5.  
  6. include('./wp-config.php');
  7. include_once(ABSPATH . WPINC . '/class-IXR.php');
  8.  
  9. // Turn off all warnings and errors.
  10. // error_reporting(0);
  11.  
  12. $post_default_title = ""; // posts submitted via the xmlrpc interface get that title
  13.  
  14. $xmlrpc_logging = 0;
  15.  
  16. function logIO($io,$msg) {
  17.     global $xmlrpc_logging;
  18.     if ($xmlrpc_logging) {
  19.         $fp = fopen("../xmlrpc.log","a+");
  20.         $date = gmdate("Y-m-d H:i:s ");
  21.         $iot = ($io == "I") ? " Input: " : " Output: ";
  22.         fwrite($fp, "\n\n".$date.$iot.$msg);
  23.         fclose($fp);
  24.     }
  25.     return true;
  26.     }
  27.  
  28. function starify($string) {
  29.     $i = strlen($string);
  30.     return str_repeat('*', $i);
  31. }
  32.  
  33. logIO("I", $HTTP_RAW_POST_DATA);
  34.  
  35.  
  36. function mkdir_p($target) {
  37.     // from php.net/mkdir user contributed notes 
  38.     if (file_exists($target)) {
  39.       if (!is_dir($target)) {
  40.         return false;
  41.       } else {
  42.         return true;
  43.       }
  44.     }
  45.  
  46.     // Attempting to create the directory may clutter up our display.
  47.     if (@mkdir($target)) {
  48.       return true;
  49.     }
  50.  
  51.     // If the above failed, attempt to create the parent node, then try again.
  52.     if (mkdir_p(dirname($target))) {
  53.       return mkdir_p($target);
  54.     }
  55.  
  56.     return false;
  57. }
  58.  
  59.  
  60. class wp_xmlrpc_server extends IXR_Server {
  61.  
  62.     function wp_xmlrpc_server() {
  63.         $this->methods = array(
  64.           // Blogger API
  65.           'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
  66.           'blogger.getUserInfo' => 'this:blogger_getUserInfo',
  67.           'blogger.getPost' => 'this:blogger_getPost',
  68.           'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
  69.           'blogger.getTemplate' => 'this:blogger_getTemplate',
  70.           'blogger.setTemplate' => 'this:blogger_setTemplate',
  71.           'blogger.newPost' => 'this:blogger_newPost',
  72.           'blogger.editPost' => 'this:blogger_editPost',
  73.           'blogger.deletePost' => 'this:blogger_deletePost',
  74.  
  75.           // MetaWeblog API (with MT extensions to structs)
  76.           'metaWeblog.newPost' => 'this:mw_newPost',
  77.           'metaWeblog.editPost' => 'this:mw_editPost',
  78.           'metaWeblog.getPost' => 'this:mw_getPost',
  79.           'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
  80.           'metaWeblog.getCategories' => 'this:mw_getCategories',
  81.           'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
  82.  
  83.           // MetaWeblog API aliases for Blogger API
  84.           // see http://www.xmlrpc.com/stories/storyReader$2460
  85.           'metaWeblog.deletePost' => 'this:blogger_deletePost',
  86.           'metaWeblog.getTemplate' => 'this:blogger_getTemplate',
  87.           'metaWeblog.setTemplate' => 'this:blogger_setTemplate',
  88.           'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
  89.  
  90.           // MovableType API
  91.           'mt.getCategoryList' => 'this:mt_getCategoryList',
  92.           'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
  93.           'mt.getPostCategories' => 'this:mt_getPostCategories',
  94.           'mt.setPostCategories' => 'this:mt_setPostCategories',
  95.           'mt.supportedMethods' => 'this:mt_supportedMethods',
  96.           'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
  97.           'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
  98.           'mt.publishPost' => 'this:mt_publishPost',
  99.  
  100.           // PingBack
  101.           'pingback.ping' => 'this:pingback_ping',
  102.           'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',
  103.  
  104.           'demo.sayHello' => 'this:sayHello',
  105.           'demo.addTwoNumbers' => 'this:addTwoNumbers'
  106.         );
  107.         $this->methods = apply_filters('xmlrpc_methods', $this->methods);
  108.         $this->IXR_Server($this->methods);
  109.     }
  110.  
  111.     function sayHello($args) {
  112.         return 'Hello!';
  113.     }
  114.  
  115.     function addTwoNumbers($args) {
  116.         $number1 = $args[0];
  117.         $number2 = $args[1];
  118.         return $number1 + $number2;
  119.     }
  120.  
  121.     function login_pass_ok($user_login, $user_pass) {
  122.       if (!user_pass_ok($user_login, $user_pass)) {
  123.         $this->error = new IXR_Error(403, 'Bad login/pass combination.');
  124.         return false;
  125.       }
  126.       return true;
  127.     }
  128.  
  129.     function escape(&$array) {
  130.         global $wpdb;
  131.  
  132.         foreach ($array as $k => $v) {
  133.             if (is_array($v)) {
  134.                 $this->escape($array[$k]);
  135.             } else if (is_object($v)) {
  136.                 //skip
  137.             } else {
  138.                 $array[$k] = $wpdb->escape($v);
  139.             }
  140.         }
  141.     }
  142.  
  143.     /* Blogger API functions
  144.      * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/
  145.      */
  146.  
  147.  
  148.     /* blogger.getUsersBlogs will make more sense once we support multiple blogs */
  149.     function blogger_getUsersBlogs($args) {
  150.  
  151.         $this->escape($args);
  152.  
  153.       $user_login = $args[1];
  154.       $user_pass  = $args[2];
  155.  
  156.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  157.         return $this->error;
  158.       }
  159.  
  160.       $user_data = get_userdatabylogin($user_login);
  161.       $is_admin = $user_data->user_level > 3;
  162.  
  163.       $struct = array(
  164.         'isAdmin'  => $is_admin,
  165.         'url'      => get_settings('home') . '/',
  166.         'blogid'   => '1',
  167.         'blogName' => get_settings('blogname')
  168.       );
  169.  
  170.       return array($struct);
  171.     }
  172.  
  173.  
  174.     /* blogger.getUsersInfo gives your client some info about you, so you don't have to */
  175.     function blogger_getUserInfo($args) {
  176.  
  177.         $this->escape($args);
  178.  
  179.       $user_login = $args[1];
  180.       $user_pass  = $args[2];
  181.  
  182.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  183.         return $this->error;
  184.       }
  185.  
  186.       $user_data = get_userdatabylogin($user_login);
  187.  
  188.       $struct = array(
  189.         'nickname'  => $user_data->user_nickname,
  190.         'userid'    => $user_data->ID,
  191.         'url'       => $user_data->user_url,
  192.         'email'     => $user_data->user_email,
  193.         'lastname'  => $user_data->user_lastname,
  194.         'firstname' => $user_data->user_firstname
  195.       );
  196.  
  197.       return $struct;
  198.     }
  199.  
  200.  
  201.     /* blogger.getPost ...gets a post */
  202.     function blogger_getPost($args) {
  203.  
  204.         $this->escape($args);
  205.  
  206.       $post_ID    = $args[1];
  207.       $user_login = $args[2];
  208.       $user_pass  = $args[3];
  209.  
  210.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  211.         return $this->error;
  212.       }
  213.  
  214.       $user_data = get_userdatabylogin($user_login);
  215.       $post_data = wp_get_single_post($post_ID, ARRAY_A);
  216.  
  217.       $categories = implode(',', wp_get_post_cats(1, $post_ID));
  218.  
  219.       $content  = '<title>'.stripslashes($post_data['post_title']).'</title>';
  220.       $content .= '<category>'.$categories.'</category>';
  221.       $content .= stripslashes($post_data['post_content']);
  222.  
  223.       $struct = array(
  224.         'userid'    => $post_data['post_author'],
  225.         'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'])),
  226.         'content'     => $content,
  227.         'postid'  => $post_data['ID']
  228.       );
  229.  
  230.       return $struct;
  231.     }
  232.  
  233.  
  234.     /* blogger.getRecentPosts ...gets recent posts */
  235.     function blogger_getRecentPosts($args) {
  236.  
  237.       global $wpdb;
  238.  
  239.         $this->escape($args);
  240.  
  241.       $blog_ID    = $args[1]; /* though we don't use it yet */
  242.       $user_login = $args[2];
  243.       $user_pass  = $args[3];
  244.       $num_posts  = $args[4];
  245.  
  246.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  247.         return $this->error;
  248.       }
  249.  
  250.       $posts_list = wp_get_recent_posts($num_posts);
  251.  
  252.       if (!$posts_list) {
  253.         $this->error = new IXR_Error(500, 'Either there are no posts, or something went wrong.');
  254.         return $this->error;
  255.       }
  256.  
  257.       foreach ($posts_list as $entry) {
  258.       
  259.         $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']);
  260.         $categories = implode(',', wp_get_post_cats(1, $entry['ID']));
  261.  
  262.         $content  = '<title>'.stripslashes($entry['post_title']).'</title>';
  263.         $content .= '<category>'.$categories.'</category>';
  264.         $content .= stripslashes($entry['post_content']);
  265.  
  266.         $struct[] = array(
  267.           'userid' => $entry['post_author'],
  268.           'dateCreated' => new IXR_Date($post_date),
  269.           'content' => $content,
  270.           'postid' => $entry['ID'],
  271.         );
  272.  
  273.       }
  274.  
  275.       $recent_posts = array();
  276.       for ($j=0; $j<count($struct); $j++) {
  277.         array_push($recent_posts, $struct[$j]);
  278.       }
  279.  
  280.       return $recent_posts;
  281.     }
  282.  
  283.  
  284.     /* blogger.getTemplate returns your blog_filename */
  285.     function blogger_getTemplate($args) {
  286.  
  287.         $this->escape($args);
  288.  
  289.       $blog_ID    = $args[1];
  290.       $user_login = $args[2];
  291.       $user_pass  = $args[3];
  292.       $template   = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */
  293.  
  294.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  295.         return $this->error;
  296.       }
  297.  
  298.       $user_data = get_userdatabylogin($user_login);
  299.  
  300.       if ($user_data->user_level < 3) {
  301.         return new IXR_Error(401, 'Sorry, users whose level is less than 3, can not edit the template.');
  302.       }
  303.  
  304.       /* warning: here we make the assumption that the weblog's URI is on the same server */
  305.       $filename = get_settings('home') . '/';
  306.       $filename = preg_replace('#http://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
  307.  
  308.       $f = fopen($filename, 'r');
  309.       $content = fread($f, filesize($filename));
  310.       fclose($f);
  311.  
  312.       /* so it is actually editable with a windows/mac client */
  313.       // FIXME: (or delete me) do we really want to cater to bad clients at the expense of good ones by BEEPing up their line breaks? commented.     $content = str_replace("\n", "\r\n", $content); 
  314.  
  315.       return $content;
  316.     }
  317.  
  318.  
  319.     /* blogger.setTemplate updates the content of blog_filename */
  320.     function blogger_setTemplate($args) {
  321.  
  322.         $this->escape($args);
  323.  
  324.       $blog_ID    = $args[1];
  325.       $user_login = $args[2];
  326.       $user_pass  = $args[3];
  327.       $content    = $args[4];
  328.       $template   = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */
  329.  
  330.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  331.         return $this->error;
  332.       }
  333.  
  334.       $user_data = get_userdatabylogin($user_login);
  335.  
  336.       if ($user_data->user_level < 3) {
  337.         return new IXR_Error(401, 'Sorry, users whose level is less than 3, can not edit the template.');
  338.       }
  339.  
  340.       /* warning: here we make the assumption that the weblog's URI is on the same server */
  341.       $filename = get_settings('home') . '/';
  342.       $filename = preg_replace('#http://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
  343.  
  344.       if ($f = fopen($filename, 'w+')) {
  345.         fwrite($f, $content);
  346.         fclose($f);
  347.       } else {
  348.         return new IXR_Error(500, 'Either the file is not writable, or something wrong happened. The file has not been updated.');
  349.       }
  350.  
  351.       return true;
  352.     }
  353.  
  354.  
  355.     /* blogger.newPost ...creates a new post */
  356.     function blogger_newPost($args) {
  357.  
  358.       global $wpdb;
  359.  
  360.         $this->escape($args);
  361.  
  362.       $blog_ID    = $args[1]; /* though we don't use it yet */
  363.       $user_login = $args[2];
  364.       $user_pass  = $args[3];
  365.       $content    = $args[4];
  366.       $publish    = $args[5];
  367.  
  368.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  369.         return $this->error;
  370.       }
  371.  
  372.       $user_data = get_userdatabylogin($user_login);
  373.       if (!user_can_create_post($user_data->ID, $blog_ID)) {
  374.         return new IXR_Error(401, 'Sorry, you can not post on this weblog or category.');
  375.       }
  376.  
  377.       $post_status = ($publish) ? 'publish' : 'draft';
  378.  
  379.       $post_author = $user_data->ID;
  380.  
  381.       $post_title = xmlrpc_getposttitle($content);
  382.       $post_category = xmlrpc_getpostcategory($content);
  383.  
  384.       $content = xmlrpc_removepostdata($content);
  385.       $post_content = apply_filters( 'content_save_pre', $content );
  386.  
  387.       $post_date = current_time('mysql');
  388.       $post_date_gmt = current_time('mysql', 1);
  389.  
  390.       $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status');
  391.  
  392.       $post_ID = wp_insert_post($post_data);
  393.  
  394.       if (!$post_ID) {
  395.         return new IXR_Error(500, 'Sorry, your entry could not be posted. Something wrong happened.');
  396.       }
  397.  
  398.       logIO('O', "Posted ! ID: $post_ID");
  399.  
  400.       return $post_ID;
  401.     }
  402.  
  403.  
  404.     /* blogger.editPost ...edits a post */
  405.     function blogger_editPost($args) {
  406.  
  407.       global $wpdb;
  408.  
  409.         $this->escape($args);
  410.  
  411.       $post_ID     = $args[1];
  412.       $user_login  = $args[2];
  413.       $user_pass   = $args[3];
  414.       $new_content = $args[4];
  415.       $publish     = $args[5];
  416.  
  417.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  418.         return $this->error;
  419.       }
  420.  
  421.       $actual_post = wp_get_single_post($post_ID,ARRAY_A);
  422.  
  423.       if (!$actual_post) {
  424.           return new IXR_Error(404, 'Sorry, no such post.');
  425.       }
  426.  
  427.         $this->escape($actual_post);
  428.  
  429.       $post_author_data = get_userdata($actual_post['post_author']);
  430.       $user_data = get_userdatabylogin($user_login);
  431.  
  432.       if (!user_can_edit_post($user_data->ID, $post_ID)) {
  433.         return new IXR_Error(401, 'Sorry, you do not have the right to edit this post.');
  434.       }
  435.  
  436.       extract($actual_post);
  437.  
  438.       $content = $newcontent;
  439.  
  440.       $post_title = xmlrpc_getposttitle($content);
  441.       $post_category = xmlrpc_getpostcategory($content);
  442.  
  443.       $content = xmlrpc_removepostdata($content);
  444.       $post_content = apply_filters( 'content_save_pre', $content );
  445.  
  446.       $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
  447.  
  448.       $result = wp_update_post($postdata);
  449.  
  450.       if (!$result) {
  451.           return new IXR_Error(500, 'For some strange yet very annoying reason, this post could not be edited.');
  452.       }
  453.  
  454.       return true;
  455.     }
  456.  
  457.  
  458.     /* blogger.deletePost ...deletes a post */
  459.     function blogger_deletePost($args) {
  460.  
  461.       global $wpdb;
  462.  
  463.         $this->escape($args);
  464.  
  465.       $post_ID     = $args[1];
  466.       $user_login  = $args[2];
  467.       $user_pass   = $args[3];
  468.       $publish     = $args[4];
  469.  
  470.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  471.         return $this->error;
  472.       }
  473.  
  474.       $actual_post = wp_get_single_post($post_ID,ARRAY_A);
  475.  
  476.       if (!$actual_post) {
  477.           return new IXR_Error(404, 'Sorry, no such post.');
  478.       }
  479.  
  480.       $user_data = get_userdatabylogin($user_login);
  481.  
  482.       if (!user_can_delete_post($user_data->ID, $post_ID)) {
  483.         return new IXR_Error(401, 'Sorry, you do not have the right to delete this post.');
  484.       }
  485.  
  486.       $result = wp_delete_post($post_ID);
  487.  
  488.       if (!$result) {
  489.           return new IXR_Error(500, 'For some strange yet very annoying reason, this post could not be deleted.');
  490.       }
  491.  
  492.       return true;
  493.     }
  494.  
  495.  
  496.  
  497.     /* MetaWeblog API functions
  498.      * specs on wherever Dave Winer wants them to be
  499.      */
  500.  
  501.     /* metaweblog.newPost creates a post */
  502.     function mw_newPost($args) {
  503.  
  504.       global $wpdb, $post_default_category;
  505.  
  506.         $this->escape($args);
  507.  
  508.       $blog_ID     = $args[0]; // we will support this in the near future
  509.       $user_login  = $args[1];
  510.       $user_pass   = $args[2];
  511.       $content_struct = $args[3];
  512.       $publish     = $args[4];
  513.  
  514.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  515.         return $this->error;
  516.       }
  517.  
  518.       $user_data = get_userdatabylogin($user_login);
  519.       if (!user_can_create_post($user_data->ID, $blog_ID)) {
  520.         return new IXR_Error(401, 'Sorry, you can not post on this weblog or category.');
  521.       }
  522.  
  523.       $post_author = $user_data->ID;
  524.  
  525.       $post_title = $content_struct['title'];
  526.       $post_content = apply_filters( 'content_save_pre', $content_struct['description'] );
  527.       $post_status = $publish ? 'publish' : 'draft';
  528.  
  529.       $post_excerpt = $content_struct['mt_excerpt'];
  530.       $post_more = $content_struct['mt_text_more'];
  531.  
  532.       $comment_status = (empty($content_struct['mt_allow_comments'])) ?
  533.         get_settings('default_comment_status')
  534.         : $content_struct['mt_allow_comments'];
  535.  
  536.       $ping_status = (empty($content_struct['mt_allow_pings'])) ?
  537.         get_settings('default_ping_status')
  538.         : $content_struct['mt_allow_pings'];
  539.  
  540.       if ($post_more) {
  541.         $post_content = $post_content . "\n<!--more-->\n" . $post_more;
  542.       }
  543.  
  544.         $to_ping = $content_struct['mt_tb_ping_urls'];
  545.  
  546.       // Do some timestamp voodoo
  547.       $dateCreatedd = $content_struct['dateCreated'];
  548.       if (!empty($dateCreatedd)) {
  549.         $dateCreated = $dateCreatedd->getIso();
  550.         $post_date     = get_date_from_gmt(iso8601_to_datetime($dateCreated));
  551.         $post_date_gmt = iso8601_to_datetime($dateCreated, GMT);
  552.       } else {
  553.         $post_date     = current_time('mysql');
  554.         $post_date_gmt = current_time('mysql', 1);
  555.       }
  556.  
  557.       $catnames = $content_struct['categories'];
  558.       logIO('O', 'Post cats: ' . printr($catnames,true));
  559.       $post_category = array();
  560.  
  561.       if (is_array($catnames)) {
  562.         foreach ($catnames as $cat) {
  563.           $post_category[] = get_cat_ID($cat);
  564.         }
  565.       }
  566.         
  567.       // We've got all the data -- post it:
  568.       $postdata = compact('post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'comment_status', 'ping_status', 'to_ping');
  569.  
  570.       $post_ID = wp_insert_post($postdata);
  571.  
  572.       if (!$post_ID) {
  573.         return new IXR_Error(500, 'Sorry, your entry could not be posted. Something wrong happened.');
  574.       }
  575.  
  576.       logIO('O', "Posted ! ID: $post_ID");
  577.  
  578.       // FIXME: do we pingback always? pingback($content, $post_ID);
  579.       // trackback_url_list($content_struct['mt_tb_ping_urls'],$post_ID);
  580.  
  581.         if ('publish' == $post_status) {
  582.             if ($post_pingback) pingback($content, $post_ID);
  583.             do_enclose( $content, $post_ID );
  584.             do_trackbacks($post_ID);
  585.             do_action('publish_post', $post_ID);
  586.         }  
  587.  
  588.       return strval($post_ID);
  589.     }
  590.  
  591.  
  592.     /* metaweblog.editPost ...edits a post */
  593.     function mw_editPost($args) {
  594.  
  595.       global $wpdb, $post_default_category;
  596.  
  597.         $this->escape($args);
  598.  
  599.       $post_ID     = $args[0];
  600.       $user_login  = $args[1];
  601.       $user_pass   = $args[2];
  602.       $content_struct = $args[3];
  603.       $publish     = $args[4];
  604.  
  605.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  606.         return $this->error;
  607.       }
  608.  
  609.       $user_data = get_userdatabylogin($user_login);
  610.       if (!user_can_edit_post($user_data->ID, $post_ID)) {
  611.         return new IXR_Error(401, 'Sorry, you can not edit this post.');
  612.       }
  613.  
  614.       $postdata = wp_get_single_post($post_ID, ARRAY_A);
  615.       extract($postdata);
  616.         $this->escape($postdata);
  617.  
  618.       $post_title = $content_struct['title'];
  619.       $post_content = apply_filters( 'content_save_pre', $content_struct['description'] );
  620.       $catnames = $content_struct['categories'];
  621.  
  622.       $post_category = array();
  623.         
  624.       if (is_array($catnames)) {
  625.         foreach ($catnames as $cat) {
  626.           $post_category[] = get_cat_ID($cat);
  627.         }
  628.       }
  629.  
  630.       $post_excerpt = $content_struct['mt_excerpt'];
  631.       $post_more = $content_struct['mt_text_more'];
  632.       $post_status = $publish ? 'publish' : 'draft';
  633.  
  634.       if ($post_more) {
  635.         $post_content = $post_content . "\n<!--more-->\n" . $post_more;
  636.       }
  637.  
  638.         $to_ping = $content_struct['mt_tb_ping_urls'];
  639.  
  640.       $comment_status = (empty($content_struct['mt_allow_comments'])) ?
  641.         get_settings('default_comment_status')
  642.         : $content_struct['mt_allow_comments'];
  643.  
  644.       $ping_status = (empty($content_struct['mt_allow_pings'])) ?
  645.         get_settings('default_ping_status')
  646.         : $content_struct['mt_allow_pings'];
  647.  
  648.       // Do some timestamp voodoo
  649.       $dateCreatedd = $content_struct['dateCreated'];
  650.       if (!empty($dateCreatedd)) {
  651.         $dateCreated = $dateCreatedd->getIso();
  652.         $post_date     = get_date_from_gmt(iso8601_to_datetime($dateCreated));
  653.         $post_date_gmt = iso8601_to_datetime($dateCreated, GMT);
  654.       } else {
  655.         $post_date     = $postdata['post_date'];
  656.         $post_date_gmt = $postdata['post_date_gmt'];
  657.       }
  658.  
  659.       // We've got all the data -- post it:
  660.       $newpost = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'comment_status', 'ping_status', 'post_date', 'post_date_gmt', 'to_ping');
  661.  
  662.       $result = wp_update_post($newpost);
  663.       if (!$result) {
  664.         return new IXR_Error(500, 'Sorry, your entry could not be edited. Something wrong happened.');
  665.       }
  666.  
  667.       logIO('O',"(MW) Edited ! ID: $post_ID");
  668.  
  669.       // FIXME: do we pingback always? pingback($content, $post_ID);
  670.       // trackback_url_list($content_struct['mt_tb_ping_urls'], $post_ID);
  671.         if ('publish' == $post_status) {
  672.             if ($post_pingback) pingback($content, $post_ID);
  673.             do_enclose( $content, $post_ID );
  674.             do_trackbacks($post_ID);
  675.             do_action('publish_post', $post_ID);
  676.         }    
  677.         do_action('edit_post', $post_ID);
  678.  
  679.       return true;
  680.     }
  681.  
  682.  
  683.     /* metaweblog.getPost ...returns a post */
  684.     function mw_getPost($args) {
  685.  
  686.       global $wpdb;
  687.  
  688.         $this->escape($args);
  689.  
  690.       $post_ID     = $args[0];
  691.       $user_login  = $args[1];
  692.       $user_pass   = $args[2];
  693.  
  694.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  695.         return $this->error;
  696.       }
  697.  
  698.       $postdata = wp_get_single_post($post_ID, ARRAY_A);
  699.  
  700.       if ($postdata['post_date'] != '') {
  701.  
  702.         $post_date = mysql2date('Ymd\TH:i:s', $postdata['post_date']);
  703.  
  704.         $categories = array();
  705.         $catids = wp_get_post_cats('', $post_ID);
  706.         foreach($catids as $catid) {
  707.           $categories[] = get_cat_name($catid);
  708.         }
  709.  
  710.         $post = get_extended($postdata['post_content']);
  711.         $link = post_permalink($postdata['ID']);
  712.  
  713.         $allow_comments = ('open' == $postdata['comment_status']) ? 1 : 0;
  714.         $allow_pings = ('open' == $postdata['ping_status']) ? 1 : 0;
  715.  
  716.         $resp = array(
  717.           'dateCreated' => new IXR_Date($post_date),
  718.           'userid' => $postdata['post_author'],
  719.           'postid' => $postdata['ID'],
  720.           'description' => $post['main'],
  721.           'title' => $postdata['post_title'],
  722.           'link' => $link,
  723.           'permaLink' => $link,
  724. // commented out because no other tool seems to use this
  725. //          'content' => $entry['post_content'],
  726.           'categories' => $categories,
  727.           'mt_excerpt' => $postdata['post_excerpt'],
  728.           'mt_text_more' => $post['extended'],
  729.           'mt_allow_comments' => $allow_comments,
  730.           'mt_allow_pings' => $allow_pings
  731.         );
  732.  
  733.         return $resp;
  734.       } else {
  735.           return new IXR_Error(404, 'Sorry, no such post.');
  736.       }
  737.     }
  738.  
  739.  
  740.     /* metaweblog.getRecentPosts ...returns recent posts */
  741.     function mw_getRecentPosts($args) {
  742.  
  743.         $this->escape($args);
  744.  
  745.       $blog_ID     = $args[0];
  746.       $user_login  = $args[1];
  747.       $user_pass   = $args[2];
  748.       $num_posts   = $args[3];
  749.  
  750.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  751.         return $this->error;
  752.       }
  753.  
  754.       $posts_list = wp_get_recent_posts($num_posts);
  755.  
  756.       if (!$posts_list) {
  757.         $this->error = new IXR_Error(500, 'Either there are no posts, or something went wrong.');
  758.         return $this->error;
  759.       }
  760.  
  761.       foreach ($posts_list as $entry) {
  762.       
  763.         $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']);
  764.         $categories = array();
  765.         $catids = wp_get_post_cats('', $entry['ID']);
  766.         foreach($catids as $catid) {
  767.           $categories[] = get_cat_name($catid);
  768.         }
  769.  
  770.         $post = get_extended($entry['post_content']);
  771.         $link = post_permalink($entry['ID']);
  772.  
  773.         $allow_comments = ('open' == $entry['comment_status']) ? 1 : 0;
  774.         $allow_pings = ('open' == $entry['ping_status']) ? 1 : 0;
  775.  
  776.         $struct[] = array(
  777.           'dateCreated' => new IXR_Date($post_date),
  778.           'userid' => $entry['post_author'],
  779.           'postid' => $entry['ID'],
  780.           'description' => $post['main'],
  781.           'title' => $entry['post_title'],
  782.           'link' => $link,
  783.           'permaLink' => $link,
  784. // commented out because no other tool seems to use this
  785. //          'content' => $entry['post_content'],
  786.           'categories' => $categories,
  787.           'mt_excerpt' => $entry['post_excerpt'],
  788.           'mt_text_more' => $post['extended'],
  789.           'mt_allow_comments' => $allow_comments,
  790.           'mt_allow_pings' => $allow_pings
  791.         );
  792.  
  793.       }
  794.  
  795.       $recent_posts = array();
  796.       for ($j=0; $j<count($struct); $j++) {
  797.         array_push($recent_posts, $struct[$j]);
  798.       }
  799.       
  800.       return $recent_posts;
  801.     }
  802.  
  803.  
  804.     /* metaweblog.getCategories ...returns the list of categories on a given weblog */
  805.     function mw_getCategories($args) {
  806.  
  807.       global $wpdb;
  808.  
  809.         $this->escape($args);
  810.  
  811.       $blog_ID     = $args[0];
  812.       $user_login  = $args[1];
  813.       $user_pass   = $args[2];
  814.  
  815.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  816.         return $this->error;
  817.       }
  818.  
  819.       $categories_struct = array();
  820.  
  821.       // FIXME: can we avoid using direct SQL there?
  822.       if ($cats = $wpdb->get_results("SELECT cat_ID,cat_name FROM $wpdb->categories", ARRAY_A)) {
  823.         foreach ($cats as $cat) {
  824.           $struct['categoryId'] = $cat['cat_ID'];
  825.           $struct['description'] = $cat['cat_name'];
  826.           $struct['categoryName'] = $cat['cat_name'];
  827.           $struct['htmlUrl'] = wp_specialchars(get_category_link($cat['cat_ID']));
  828.           $struct['rssUrl'] = wp_specialchars(get_category_rss_link(false, $cat['cat_ID'], $cat['cat_name']));
  829.  
  830.           $categories_struct[] = $struct;
  831.         }
  832.       }
  833.  
  834.       return $categories_struct;
  835.     }
  836.  
  837.  
  838.     /* metaweblog.newMediaObject uploads a file, following your settings */
  839.     function mw_newMediaObject($args) {
  840.       // adapted from a patch by Johann Richard
  841.       // http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/
  842.  
  843.         global $wpdb;
  844.  
  845.       $blog_ID     = $wpdb->escape($args[0]);
  846.       $user_login  = $wpdb->escape($args[1]);
  847.         $user_pass   = $wpdb->escape($args[2]);
  848.       $data        = $args[3];
  849.  
  850.       $name = $data['name'];
  851.       $type = $data['type'];
  852.       $bits = $data['bits'];
  853.  
  854.       $file_realpath = get_settings('fileupload_realpath'); 
  855.       $file_url = get_settings('fileupload_url');
  856.  
  857.       logIO('O', '(MW) Received '.strlen($bits).' bytes');
  858.  
  859.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  860.         return $this->error;
  861.       }
  862.  
  863.       $user_data = get_userdatabylogin($user_login);
  864.  
  865.       if(!get_settings('use_fileupload')) {
  866.         // Uploads not allowed
  867.         logIO('O', '(MW) Uploads not allowed');
  868.         $this->error = new IXR_Error(405, 'No uploads allowed for this site.');
  869.         return $this->error;
  870.       } 
  871.  
  872.       if(get_settings('fileupload_minlevel') > $user_data->user_level) {
  873.         // User has not enough privileges
  874.         logIO('O', '(MW) Not enough privilege: user level too low');
  875.         $this->error = new IXR_Error(401, 'You are not allowed to upload files to this site.');
  876.         return $this->error;
  877.       }
  878.  
  879.       if(trim($file_realpath) == '' || trim($file_url) == '' ) {
  880.         // WordPress is not correctly configured
  881.         logIO('O', '(MW) Bad configuration. Real/URL path not defined');
  882.         $this->error = new IXR_Error(500, 'Please configure WordPress with valid paths for file upload.');
  883.         return $this->error;
  884.       }
  885.  
  886.       $prefix = '/';
  887.  
  888.       if(!empty($name)) {
  889.         // Create the path
  890.         $localpath = $file_realpath.$prefix.$name;
  891.         $url = $file_url.$prefix.$name;
  892.  
  893.         if (mkdir_p(dirname($localpath))) {
  894.  
  895.           /* encode & write data (binary) */
  896.           $ifp = fopen($localpath, 'wb');
  897.           $success = fwrite($ifp, $bits);
  898.           fclose($ifp);
  899.           @chmod($localpath, 0666);
  900.  
  901.           if($success) {
  902.             $resp = array('url' => $url);
  903.             return $resp;
  904.           } else {
  905.             logIO('O', '(MW) Could not write file '.$name.' to '.$localpath);
  906.             return new IXR_Error(500, 'Could not write file '.$name);
  907.           }
  908.  
  909.         } else {
  910.           return new IXR_Error(500, 'Could not create directories for '.$name);
  911.         }
  912.       }
  913.     }
  914.  
  915.  
  916.  
  917.     /* MovableType API functions
  918.      * specs on http://www.movabletype.org/docs/mtmanual_programmatic.html
  919.      */
  920.  
  921.     /* mt.getRecentPostTitles ...returns recent posts' titles */
  922.     function mt_getRecentPostTitles($args) {
  923.  
  924.         $this->escape($args);
  925.  
  926.       $blog_ID     = $args[0];
  927.       $user_login  = $args[1];
  928.       $user_pass   = $args[2];
  929.       $num_posts   = $args[3];
  930.  
  931.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  932.         return $this->error;
  933.       }
  934.  
  935.       $posts_list = wp_get_recent_posts($num_posts);
  936.  
  937.       if (!$posts_list) {
  938.         $this->error = new IXR_Error(500, 'Either there are no posts, or something went wrong.');
  939.         return $this->error;
  940.       }
  941.  
  942.       foreach ($posts_list as $entry) {
  943.       
  944.         $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']);
  945.  
  946.         $struct[] = array(
  947.           'dateCreated' => new IXR_Date($post_date),
  948.           'userid' => $entry['post_author'],
  949.           'postid' => $entry['ID'],
  950.           'title' => $entry['post_title'],
  951.         );
  952.  
  953.       }
  954.  
  955.       $recent_posts = array();
  956.       for ($j=0; $j<count($struct); $j++) {
  957.         array_push($recent_posts, $struct[$j]);
  958.       }
  959.       
  960.       return $recent_posts;
  961.     }
  962.  
  963.  
  964.     /* mt.getCategoryList ...returns the list of categories on a given weblog */
  965.     function mt_getCategoryList($args) {
  966.  
  967.       global $wpdb;
  968.  
  969.         $this->escape($args);
  970.  
  971.       $blog_ID     = $args[0];
  972.       $user_login  = $args[1];
  973.       $user_pass   = $args[2];
  974.  
  975.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  976.         return $this->error;
  977.       }
  978.  
  979.       $categories_struct = array();
  980.  
  981.       // FIXME: can we avoid using direct SQL there?
  982.       if ($cats = $wpdb->get_results("SELECT cat_ID, cat_name FROM $wpdb->categories", ARRAY_A)) {
  983.         foreach ($cats as $cat) {
  984.           $struct['categoryId'] = $cat['cat_ID'];
  985.           $struct['categoryName'] = $cat['cat_name'];
  986.  
  987.           $categories_struct[] = $struct;
  988.         }
  989.       }
  990.  
  991.       return $categories_struct;
  992.     }
  993.  
  994.  
  995.     /* mt.getPostCategories ...returns a post's categories */
  996.     function mt_getPostCategories($args) {
  997.  
  998.         $this->escape($args);
  999.  
  1000.       $post_ID     = $args[0];
  1001.       $user_login  = $args[1];
  1002.       $user_pass   = $args[2];
  1003.  
  1004.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  1005.         return $this->error;
  1006.       }
  1007.  
  1008.       $categories = array();
  1009.       $catids = wp_get_post_cats('', intval($post_ID));
  1010.       // first listed category will be the primary category
  1011.       $isPrimary = true;
  1012.       foreach($catids as $catid) {
  1013.         $categories[] = array(
  1014.           'categoryName' => get_cat_name($catid),
  1015.           'categoryId' => $catid,
  1016.           'isPrimary' => $isPrimary
  1017.         );
  1018.         $isPrimary = false;
  1019.       }
  1020.  
  1021.       return $categories;
  1022.     }
  1023.  
  1024.  
  1025.     /* mt.setPostCategories ...sets a post's categories */
  1026.     function mt_setPostCategories($args) {
  1027.  
  1028.         $this->escape($args);
  1029.  
  1030.       $post_ID     = $args[0];
  1031.       $user_login  = $args[1];
  1032.       $user_pass   = $args[2];
  1033.       $categories  = $args[3];
  1034.  
  1035.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  1036.         return $this->error;
  1037.       }
  1038.  
  1039.       $user_data = get_userdatabylogin($user_login);
  1040.       if (!user_can_edit_post($user_data->ID, $post_ID)) {
  1041.         return new IXR_Error(401, 'Sorry, you can not edit this post.');
  1042.       }
  1043.  
  1044.       foreach($categories as $cat) {
  1045.         $catids[] = $cat['categoryId'];
  1046.       }
  1047.     
  1048.       wp_set_post_cats('', $post_ID, $catids);
  1049.  
  1050.       return true;
  1051.     }
  1052.  
  1053.  
  1054.     /* mt.supportedMethods ...returns an array of methods supported by this server */
  1055.     function mt_supportedMethods($args) {
  1056.  
  1057.       $supported_methods = array();
  1058.       foreach($this->methods as $key=>$value) {
  1059.         $supported_methods[] = $key;
  1060.       }
  1061.  
  1062.       return $supported_methods;
  1063.     }
  1064.  
  1065.  
  1066.     /* mt.supportedTextFilters ...returns an empty array because we don't
  1067.        support per-post text filters yet */
  1068.     function mt_supportedTextFilters($args) {
  1069.       return array();
  1070.     }
  1071.  
  1072.  
  1073.     /* mt.getTrackbackPings ...returns trackbacks sent to a given post */
  1074.     function mt_getTrackbackPings($args) {
  1075.  
  1076.       global $wpdb;
  1077.  
  1078.       $post_ID = intval($args);
  1079.  
  1080.       $actual_post = wp_get_single_post($post_ID, ARRAY_A);
  1081.  
  1082.       if (!$actual_post) {
  1083.           return new IXR_Error(404, 'Sorry, no such post.');
  1084.       }
  1085.  
  1086.       $comments = $wpdb->get_results("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = $post_ID");
  1087.  
  1088.       if (!$comments) {
  1089.           return array();
  1090.       }
  1091.  
  1092.       $trackback_pings = array();
  1093.       foreach($comments as $comment) {
  1094.         if ( 'trackback' == $comment->comment_type ) {
  1095.           $content = $comment->comment_content;
  1096.           $title = substr($content, 8, (strpos($content, '</strong>') - 8));
  1097.           $trackback_pings[] = array(
  1098.             'pingTitle' => $title,
  1099.             'pingURL'   => $comment->comment_author_url,
  1100.             'pingIP'    => $comment->comment_author_IP
  1101.           );
  1102.         }
  1103.       }
  1104.  
  1105.       return $trackback_pings;
  1106.     }
  1107.  
  1108.  
  1109.     /* mt.publishPost ...sets a post's publish status to 'publish' */
  1110.     function mt_publishPost($args) {
  1111.  
  1112.         $this->escape($args);
  1113.  
  1114.       $post_ID     = $args[0];
  1115.       $user_login  = $args[1];
  1116.       $user_pass   = $args[2];
  1117.  
  1118.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  1119.         return $this->error;
  1120.       }
  1121.  
  1122.       $user_data = get_userdatabylogin($user_login);
  1123.       if (!user_can_edit_post($user_data->ID, $post_ID)) {
  1124.         return new IXR_Error(401, 'Sorry, you can not edit this post.');
  1125.       }
  1126.  
  1127.       $postdata = wp_get_single_post($post_ID,ARRAY_A);
  1128.  
  1129.       $postdata['post_status'] = 'publish';
  1130.  
  1131.       // retain old cats
  1132.       $cats = wp_get_post_cats('',$post_ID);
  1133.       $postdata['post_category'] = $cats;
  1134.         $this->escape($postdata);
  1135.  
  1136.       $result = wp_update_post($postdata);
  1137.  
  1138.       return $result;
  1139.     }
  1140.  
  1141.  
  1142.  
  1143.     /* PingBack functions
  1144.      * specs on www.hixie.ch/specs/pingback/pingback
  1145.      */
  1146.  
  1147.     /* pingback.ping gets a pingback and registers it */
  1148.     function pingback_ping($args) {
  1149.         global $wpdb, $wp_version; 
  1150.  
  1151.         $this->escape($args);
  1152.  
  1153.         $pagelinkedfrom = $args[0];
  1154.         $pagelinkedto   = $args[1];
  1155.  
  1156.         $title = '';
  1157.  
  1158.         $pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom);
  1159.         $pagelinkedto   = preg_replace('#&([^amp\;])#is', '&$1', $pagelinkedto);
  1160.  
  1161.         $error_code = -1;
  1162.  
  1163.         // Check if the page linked to is in our site
  1164.         $pos1 = strpos($pagelinkedto, str_replace('http://', '', str_replace('www.', '', get_settings('home'))));
  1165.         if( !$pos1 )
  1166.               return new IXR_Error(0, 'Is there no link to us?');
  1167.  
  1168.         // let's find which post is linked to
  1169.         // FIXME: does url_to_postid() cover all these cases already?
  1170.         //        if so, then let's use it and drop the old code.
  1171.         $urltest = parse_url($pagelinkedto);
  1172.         if ($post_ID = url_to_postid($pagelinkedto)) {
  1173.             $way = 'url_to_postid()';
  1174.         } elseif (preg_match('#p/[0-9]{1,}#', $urltest['path'], $match)) {
  1175.             // the path defines the post_ID (archives/p/XXXX)
  1176.             $blah = explode('/', $match[0]);
  1177.             $post_ID = $blah[1];
  1178.             $way = 'from the path';
  1179.         } elseif (preg_match('#p=[0-9]{1,}#', $urltest['query'], $match)) {
  1180.             // the querystring defines the post_ID (?p=XXXX)
  1181.             $blah = explode('=', $match[0]);
  1182.             $post_ID = $blah[1];
  1183.             $way = 'from the querystring';
  1184.         } elseif (isset($urltest['fragment'])) {
  1185.             // an #anchor is there, it's either...
  1186.             if (intval($urltest['fragment'])) {
  1187.                 // ...an integer #XXXX (simpliest case)
  1188.                 $post_ID = $urltest['fragment'];
  1189.                 $way = 'from the fragment (numeric)';
  1190.             } elseif (preg_match('/post-[0-9]+/',$urltest['fragment'])) {
  1191.                 // ...a post id in the form 'post-###'
  1192.                 $post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']);
  1193.                 $way = 'from the fragment (post-###)';
  1194.             } elseif (is_string($urltest['fragment'])) {
  1195.                 // ...or a string #title, a little more complicated
  1196.                 $title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']);
  1197.                 $sql = "SELECT ID FROM $wpdb->posts WHERE post_title RLIKE '$title'";
  1198.                 if (! ($post_ID = $wpdb->get_var($sql)) ) {
  1199.                     // returning unknown error '0' is better than die()ing
  1200.                       return new IXR_Error(0, '');
  1201.                 }
  1202.                 $way = 'from the fragment (title)';
  1203.             }
  1204.         } else {
  1205.             // TODO: Attempt to extract a post ID from the given URL
  1206.               return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.');
  1207.         }
  1208.         $post_ID = (int) $post_ID;
  1209.  
  1210.  
  1211.         logIO("O","(PB) URI='$pagelinkedto' ID='$post_ID' Found='$way'");
  1212.  
  1213.         $post = get_post($post_ID);
  1214.  
  1215.         if ( !$post ) // Post_ID not found
  1216.               return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.');
  1217.  
  1218.         // Check if pings are on
  1219.         if ( 'closed' == $post->ping_status )
  1220.               return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.');
  1221.  
  1222.         // Let's check that the remote site didn't already pingback this entry
  1223.         $result = $wpdb->get_results("SELECT * FROM $wpdb->comments WHERE comment_post_ID = '$post_ID' AND comment_author_url = '$pagelinkedfrom'");
  1224.  
  1225.         if ( $wpdb->num_rows ) // We already have a Pingback from this URL
  1226.               return new IXR_Error(48, 'The pingback has already been registered.');
  1227.  
  1228.         // very stupid, but gives time to the 'from' server to publish !
  1229.         sleep(1);
  1230.  
  1231.         // Let's check the remote site
  1232.         $linea = wp_remote_fopen( $pagelinkedfrom );
  1233.         if ( !$linea )
  1234.               return new IXR_Error(16, 'The source URI does not exist.');
  1235.  
  1236.         // Work around bug in strip_tags():
  1237.         $linea = str_replace('<!DOC', '<DOC', $linea);
  1238.         $linea = preg_replace( '/[\s\r\n\t]+/', ' ', $linea ); // normalize spaces
  1239.         $linea = preg_replace( "/ <(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $linea );
  1240.  
  1241.         preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle);
  1242.         $title = $matchtitle[1];
  1243.         if ( empty( $title ) )
  1244.             return new IXR_Error(32, 'We cannot find a title on that page.');
  1245.  
  1246.         $linea = strip_tags( $linea, '<a>' ); // just keep the tag we need
  1247.  
  1248.         $p = explode( "\n\n", $linea );
  1249.         
  1250.         $sem_regexp_pb = "/(\\/|\\\|\*|\?|\+|\.|\^|\\$|\(|\)|\[|\]|\||\{|\})/";
  1251.         $sem_regexp_fix = "\\\\$1";
  1252.         $link = preg_replace( $sem_regexp_pb, $sem_regexp_fix, $pagelinkedfrom );
  1253.         
  1254.         $finished = false;
  1255.         foreach ( $p as $para ) {
  1256.             if ( $finished )
  1257.                 continue;
  1258.             if ( strstr( $para, $pagelinkedto ) ) {
  1259.                 $context = preg_replace( "/.*<a[^>]+".$link."[^>]*>([^>]+)<\/a>.*/", "$1", $para );
  1260.                 $excerpt = strip_tags( $para );
  1261.                 $excerpt = trim( $excerpt );
  1262.                 $use     = preg_quote( $context );
  1263.                 $excerpt = preg_replace("|.*?\s(.{0,100}$use.{0,100})\s|s", "$1", $excerpt);
  1264.                 $finished = true;
  1265.             }
  1266.         }
  1267.  
  1268.         if ( empty($context) )  // URL pattern not found
  1269.             return new IXR_Error(17, 'The source URI does not contain a link to the target URI, and so cannot be used as a source.');
  1270.  
  1271.         $pagelinkedfrom = preg_replace('#&([^amp\;])#is', '&$1', $pagelinkedfrom);
  1272.  
  1273.         $context = '[...] ' . wp_specialchars( $excerpt ) . ' [...]';
  1274.         $original_pagelinkedfrom = $pagelinkedfrom;
  1275.         $pagelinkedfrom = addslashes( $pagelinkedfrom );
  1276.         $original_title = $title;
  1277.  
  1278.         $comment_post_ID = $post_ID;
  1279.         $comment_author = $title;
  1280.         $comment_author_url = $pagelinkedfrom;
  1281.         $comment_content = $context;
  1282.         $comment_type = 'pingback';
  1283.  
  1284.         $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_content', 'comment_type');
  1285.  
  1286.         wp_new_comment($commentdata);
  1287.         do_action('pingback_post', $wpdb->insert_id);
  1288.         
  1289.         return "Pingback from $pagelinkedfrom to $pagelinkedto registered. Keep the web talking! :-)";
  1290.     }
  1291.  
  1292.  
  1293.     /* pingback.extensions.getPingbacks returns an array of URLs
  1294.        that pingbacked the given URL
  1295.        specs on http://www.aquarionics.com/misc/archives/blogite/0198.html */
  1296.     function pingback_extensions_getPingbacks($args) {
  1297.  
  1298.         global $wpdb;
  1299.  
  1300.         $this->escape($args);
  1301.  
  1302.         $url = $args;
  1303.  
  1304.         $post_ID = url_to_postid($url);
  1305.         if (!$post_ID) {
  1306.             // We aren't sure that the resource is available and/or pingback enabled
  1307.               return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.');
  1308.         }
  1309.  
  1310.         $actual_post = wp_get_single_post($post_ID, ARRAY_A);
  1311.  
  1312.         if (!$actual_post) {
  1313.             // No such post = resource not found
  1314.               return new IXR_Error(32, 'The specified target URI does not exist.');
  1315.         }
  1316.  
  1317.         $comments = $wpdb->get_results("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = $post_ID");
  1318.  
  1319.         if (!$comments) {
  1320.             return array();
  1321.         }
  1322.  
  1323.         $pingbacks = array();
  1324.         foreach($comments as $comment) {
  1325.             if ( 'pingback' == $comment->comment_type )
  1326.                 $pingbacks[] = $comment->comment_author_url;
  1327.         }
  1328.  
  1329.         return $pingbacks;
  1330.     }
  1331. }
  1332.  
  1333.  
  1334. $wp_xmlrpc_server = new wp_xmlrpc_server();
  1335.  
  1336. ?>
  1337.