home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Blogs / wordpress2.6.exe / wordpress2.6 / xmlrpc.php < prev   
Encoding:
PHP Script  |  2008-07-25  |  73.6 KB  |  2,644 lines

  1. <?php
  2. /**
  3.  * XML-RPC protocol support for WordPress
  4.  *
  5.  * @license GPL v2 <./license.txt>
  6.  * @package WordPress
  7.  */
  8.  
  9. /**
  10.  * Whether this is a XMLRPC Request
  11.  *
  12.  * @var bool
  13.  */
  14. define('XMLRPC_REQUEST', true);
  15.  
  16. // Some browser-embedded clients send cookies. We don't want them.
  17. $_COOKIE = array();
  18.  
  19. // A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default,
  20. // but we can do it ourself.
  21. if ( !isset( $HTTP_RAW_POST_DATA ) ) {
  22.     $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
  23. }
  24.  
  25. // fix for mozBlog and other cases where '<?xml' isn't on the very first line
  26. if ( isset($HTTP_RAW_POST_DATA) )
  27.     $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);
  28.  
  29. /** Include the bootstrap for setting up WordPress environment */
  30. include('./wp-load.php');
  31.  
  32. if ( isset( $_GET['rsd'] ) ) { // http://archipelago.phrasewise.com/rsd
  33. header('Content-Type: text/xml; charset=' . get_option('blog_charset'), true);
  34. ?>
  35. <?php echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>
  36. <rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
  37.   <service>
  38.     <engineName>WordPress</engineName>
  39.     <engineLink>http://wordpress.org/</engineLink>
  40.     <homePageLink><?php bloginfo_rss('url') ?></homePageLink>
  41.     <apis>
  42.       <api name="WordPress" blogID="1" preferred="true" apiLink="<?php echo site_url('xmlrpc.php') ?>" />
  43.       <api name="Movable Type" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php') ?>" />
  44.       <api name="MetaWeblog" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php') ?>" />
  45.       <api name="Blogger" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php') ?>" />
  46.       <api name="Atom" blogID="" preferred="false" apiLink="<?php echo apply_filters('atom_service_url', site_url('wp-app.php/service') ) ?>" />
  47.     </apis>
  48.   </service>
  49. </rsd>
  50. <?php
  51. exit;
  52. }
  53.  
  54. include_once(ABSPATH . 'wp-admin/includes/admin.php');
  55. include_once(ABSPATH . WPINC . '/class-IXR.php');
  56.  
  57. // Turn off all warnings and errors.
  58. // error_reporting(0);
  59.  
  60. /**
  61.  * Posts submitted via the xmlrpc interface get that title
  62.  * @name post_default_title
  63.  * @var string
  64.  */
  65. $post_default_title = "";
  66.  
  67. /**
  68.  * Whether to enable XMLRPC Logging.
  69.  *
  70.  * @name xmlrpc_logging
  71.  * @var int|bool
  72.  */
  73. $xmlrpc_logging = 0;
  74.  
  75. /**
  76.  * logIO() - Writes logging info to a file.
  77.  *
  78.  * @uses $xmlrpc_logging
  79.  * @package WordPress
  80.  * @subpackage Logging
  81.  *
  82.  * @param string $io Whether input or output
  83.  * @param string $msg Information describing logging reason.
  84.  * @return bool Always return true
  85.  */
  86. function logIO($io,$msg) {
  87.     global $xmlrpc_logging;
  88.     if ($xmlrpc_logging) {
  89.         $fp = fopen("../xmlrpc.log","a+");
  90.         $date = gmdate("Y-m-d H:i:s ");
  91.         $iot = ($io == "I") ? " Input: " : " Output: ";
  92.         fwrite($fp, "\n\n".$date.$iot.$msg);
  93.         fclose($fp);
  94.     }
  95.     return true;
  96. }
  97.  
  98. if ( isset($HTTP_RAW_POST_DATA) )
  99.     logIO("I", $HTTP_RAW_POST_DATA);
  100.  
  101. /**
  102.  * @internal
  103.  * Left undocumented to work on later. If you want to finish, then please do so.
  104.  *
  105.  * @package WordPress
  106.  * @subpackage Publishing
  107.  */
  108. class wp_xmlrpc_server extends IXR_Server {
  109.  
  110.     function wp_xmlrpc_server() {
  111.         $this->methods = array(
  112.             // WordPress API
  113.             'wp.getUsersBlogs'        => 'this:wp_getUsersBlogs',
  114.             'wp.getPage'            => 'this:wp_getPage',
  115.             'wp.getPages'            => 'this:wp_getPages',
  116.             'wp.newPage'            => 'this:wp_newPage',
  117.             'wp.deletePage'            => 'this:wp_deletePage',
  118.             'wp.editPage'            => 'this:wp_editPage',
  119.             'wp.getPageList'        => 'this:wp_getPageList',
  120.             'wp.getAuthors'            => 'this:wp_getAuthors',
  121.             'wp.getCategories'        => 'this:mw_getCategories',        // Alias
  122.             'wp.newCategory'        => 'this:wp_newCategory',
  123.             'wp.deleteCategory'        => 'this:wp_deleteCategory',
  124.             'wp.suggestCategories'    => 'this:wp_suggestCategories',
  125.             'wp.uploadFile'            => 'this:mw_newMediaObject',    // Alias
  126.             'wp.getCommentCount'    => 'this:wp_getCommentCount',
  127.             'wp.getPostStatusList'    => 'this:wp_getPostStatusList',
  128.             'wp.getPageStatusList'    => 'this:wp_getPageStatusList',
  129.             'wp.getPageTemplates'    => 'this:wp_getPageTemplates',
  130.             'wp.getOptions'            => 'this:wp_getOptions',
  131.             'wp.setOptions'            => 'this:wp_setOptions',
  132.  
  133.             // Blogger API
  134.             'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
  135.             'blogger.getUserInfo' => 'this:blogger_getUserInfo',
  136.             'blogger.getPost' => 'this:blogger_getPost',
  137.             'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
  138.             'blogger.getTemplate' => 'this:blogger_getTemplate',
  139.             'blogger.setTemplate' => 'this:blogger_setTemplate',
  140.             'blogger.newPost' => 'this:blogger_newPost',
  141.             'blogger.editPost' => 'this:blogger_editPost',
  142.             'blogger.deletePost' => 'this:blogger_deletePost',
  143.  
  144.             // MetaWeblog API (with MT extensions to structs)
  145.             'metaWeblog.newPost' => 'this:mw_newPost',
  146.             'metaWeblog.editPost' => 'this:mw_editPost',
  147.             'metaWeblog.getPost' => 'this:mw_getPost',
  148.             'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
  149.             'metaWeblog.getCategories' => 'this:mw_getCategories',
  150.             'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
  151.  
  152.             // MetaWeblog API aliases for Blogger API
  153.             // see http://www.xmlrpc.com/stories/storyReader$2460
  154.             'metaWeblog.deletePost' => 'this:blogger_deletePost',
  155.             'metaWeblog.getTemplate' => 'this:blogger_getTemplate',
  156.             'metaWeblog.setTemplate' => 'this:blogger_setTemplate',
  157.             'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
  158.  
  159.             // MovableType API
  160.             'mt.getCategoryList' => 'this:mt_getCategoryList',
  161.             'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
  162.             'mt.getPostCategories' => 'this:mt_getPostCategories',
  163.             'mt.setPostCategories' => 'this:mt_setPostCategories',
  164.             'mt.supportedMethods' => 'this:mt_supportedMethods',
  165.             'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
  166.             'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
  167.             'mt.publishPost' => 'this:mt_publishPost',
  168.  
  169.             // PingBack
  170.             'pingback.ping' => 'this:pingback_ping',
  171.             'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',
  172.  
  173.             'demo.sayHello' => 'this:sayHello',
  174.             'demo.addTwoNumbers' => 'this:addTwoNumbers'
  175.         );
  176.  
  177.         $this->initialise_blog_option_info( );
  178.         $this->methods = apply_filters('xmlrpc_methods', $this->methods);
  179.         $this->IXR_Server($this->methods);
  180.     }
  181.  
  182.     function sayHello($args) {
  183.         return 'Hello!';
  184.     }
  185.  
  186.     function addTwoNumbers($args) {
  187.         $number1 = $args[0];
  188.         $number2 = $args[1];
  189.         return $number1 + $number2;
  190.     }
  191.  
  192.     function login_pass_ok($user_login, $user_pass) {
  193.         if ( !get_option( 'enable_xmlrpc' ) ) {
  194.             $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this blog.  An admin user can enable them at %s'),  admin_url('options-writing.php') ) );
  195.             return false;
  196.         }
  197.  
  198.         if (!user_pass_ok($user_login, $user_pass)) {
  199.             $this->error = new IXR_Error(403, __('Bad login/pass combination.'));
  200.             return false;
  201.         }
  202.         return true;
  203.     }
  204.  
  205.     function escape(&$array) {
  206.         global $wpdb;
  207.  
  208.         if(!is_array($array)) {
  209.             return($wpdb->escape($array));
  210.         }
  211.         else {
  212.             foreach ( (array) $array as $k => $v ) {
  213.                 if (is_array($v)) {
  214.                     $this->escape($array[$k]);
  215.                 } else if (is_object($v)) {
  216.                     //skip
  217.                 } else {
  218.                     $array[$k] = $wpdb->escape($v);
  219.                 }
  220.             }
  221.         }
  222.     }
  223.  
  224.     function get_custom_fields($post_id) {
  225.         $post_id = (int) $post_id;
  226.  
  227.         $custom_fields = array();
  228.  
  229.         foreach ( (array) has_meta($post_id) as $meta ) {
  230.             // Don't expose protected fields.
  231.             if ( strpos($meta['meta_key'], '_wp_') === 0 ) {
  232.                 continue;
  233.             }
  234.  
  235.             $custom_fields[] = array(
  236.                 "id"    => $meta['meta_id'],
  237.                 "key"   => $meta['meta_key'],
  238.                 "value" => $meta['meta_value']
  239.             );
  240.         }
  241.  
  242.         return $custom_fields;
  243.     }
  244.  
  245.     function set_custom_fields($post_id, $fields) {
  246.         $post_id = (int) $post_id;
  247.  
  248.         foreach ( (array) $fields as $meta ) {
  249.             if ( isset($meta['id']) ) {
  250.                 $meta['id'] = (int) $meta['id'];
  251.  
  252.                 if ( isset($meta['key']) ) {
  253.                     update_meta($meta['id'], $meta['key'], $meta['value']);
  254.                 }
  255.                 else {
  256.                     delete_meta($meta['id']);
  257.                 }
  258.             }
  259.             else {
  260.                 $_POST['metakeyinput'] = $meta['key'];
  261.                 $_POST['metavalue'] = $meta['value'];
  262.                 add_meta($post_id);
  263.             }
  264.         }
  265.     }
  266.  
  267.     function initialise_blog_option_info( ) {
  268.         global $wp_version;
  269.  
  270.         $this->blog_options = array(
  271.             // Read only options
  272.             'software_name'        => array(
  273.                 'desc'            => __( 'Software Name' ),
  274.                 'readonly'        => true,
  275.                 'value'            => 'WordPress'
  276.             ),
  277.             'software_version'    => array(
  278.                 'desc'            => __( 'Software Version' ),
  279.                 'readonly'        => true,
  280.                 'value'            => $wp_version
  281.             ),
  282.             'blog_url'            => array(
  283.                 'desc'            => __( 'Blog URL' ),
  284.                 'readonly'        => true,
  285.                 'option'        => 'siteurl'
  286.             ),
  287.  
  288.             // Updatable options
  289.             'time_zone'            => array(
  290.                 'desc'            => __( 'Time Zone' ),
  291.                 'readonly'        => false,
  292.                 'option'        => 'gmt_offset'
  293.             ),
  294.             'blog_title'        => array(
  295.                 'desc'            => __( 'Blog Title' ),
  296.                 'readonly'        => false,
  297.                 'option'            => 'blogname'
  298.             ),
  299.             'blog_tagline'        => array(
  300.                 'desc'            => __( 'Blog Tagline' ),
  301.                 'readonly'        => false,
  302.                 'option'        => 'blogdescription'
  303.             ),
  304.             'date_format'        => array(
  305.                 'desc'            => __( 'Date Format' ),
  306.                 'readonly'        => false,
  307.                 'option'        => 'date_format'
  308.             ),
  309.             'time_format'        => array(
  310.                 'desc'            => __( 'Time Format' ),
  311.                 'readonly'        => false,
  312.                 'option'        => 'time_format'
  313.             )
  314.         );
  315.  
  316.         $this->blog_options = apply_filters( 'xmlrpc_blog_options', $this->blog_options );
  317.     }
  318.  
  319.     /**
  320.      * WordPress XML-RPC API
  321.      * wp_getUsersBlogs
  322.      */
  323.     function wp_getUsersBlogs( $args ) {
  324.         // If this isn't on WPMU then just use blogger_getUsersBlogs
  325.         if( !function_exists( 'is_site_admin' ) ) {
  326.             array_unshift( $args, 1 );
  327.             return $this->blogger_getUsersBlogs( $args );
  328.         }
  329.  
  330.         $this->escape( $args );
  331.  
  332.         $username = $args[0];
  333.         $password = $args[1];
  334.  
  335.         if( !$this->login_pass_ok( $username, $password ) )
  336.             return $this->error;
  337.  
  338.         do_action( 'xmlrpc_call', 'wp.getUsersBlogs' );
  339.  
  340.         $user = set_current_user( 0, $username );
  341.  
  342.         $blogs = (array) get_blogs_of_user( $user->ID );
  343.         $struct = array( );
  344.  
  345.         foreach( $blogs as $blog ) {
  346.             // Don't include blogs that aren't hosted at this site
  347.             if( $blog->site_id != 1 )
  348.                 continue;
  349.  
  350.             $blog_id = $blog->userblog_id;
  351.             switch_to_blog($blog_id);
  352.             $is_admin = current_user_can('level_8');
  353.  
  354.             $struct[] = array(
  355.                 'isAdmin'        => $is_admin,
  356.                 'url'            => get_option( 'home' ) . '/',
  357.                 'blogid'        => $blog_id,
  358.                 'blogName'        => get_option( 'blogname' ),
  359.                 'xmlrpc'        => get_option( 'home' ) . '/xmlrpc.php'
  360.             );
  361.         }
  362.  
  363.         return $struct;
  364.     }
  365.  
  366.     /**
  367.      * WordPress XML-RPC API
  368.      * wp_getPage
  369.      */
  370.     function wp_getPage($args) {
  371.         $this->escape($args);
  372.  
  373.         $blog_id    = (int) $args[0];
  374.         $page_id    = (int) $args[1];
  375.         $username    = $args[2];
  376.         $password    = $args[3];
  377.  
  378.         if(!$this->login_pass_ok($username, $password)) {
  379.             return($this->error);
  380.         }
  381.  
  382.         set_current_user( 0, $username );
  383.         if( !current_user_can( 'edit_page', $page_id ) )
  384.             return new IXR_Error( 401, __( 'Sorry, you can not edit this page.' ) );
  385.  
  386.         do_action('xmlrpc_call', 'wp.getPage');
  387.  
  388.         // Lookup page info.
  389.         $page = get_page($page_id);
  390.  
  391.         // If we found the page then format the data.
  392.         if($page->ID && ($page->post_type == "page")) {
  393.             // Get all of the page content and link.
  394.             $full_page = get_extended($page->post_content);
  395.             $link = post_permalink($page->ID);
  396.  
  397.             // Get info the page parent if there is one.
  398.             $parent_title = "";
  399.             if(!empty($page->post_parent)) {
  400.                 $parent = get_page($page->post_parent);
  401.                 $parent_title = $parent->post_title;
  402.             }
  403.  
  404.             // Determine comment and ping settings.
  405.             $allow_comments = ("open" == $page->comment_status) ? 1 : 0;
  406.             $allow_pings = ("open" == $page->ping_status) ? 1 : 0;
  407.  
  408.             // Format page date.
  409.             $page_date = mysql2date("Ymd\TH:i:s", $page->post_date);
  410.             $page_date_gmt = mysql2date("Ymd\TH:i:s", $page->post_date_gmt);
  411.  
  412.             // Pull the categories info together.
  413.             $categories = array();
  414.             foreach(wp_get_post_categories($page->ID) as $cat_id) {
  415.                 $categories[] = get_cat_name($cat_id);
  416.             }
  417.  
  418.             // Get the author info.
  419.             $author = get_userdata($page->post_author);
  420.  
  421.             $page_template = get_post_meta( $page->ID, '_wp_page_template', true );
  422.             if( empty( $page_template ) )
  423.                 $page_template = 'default';
  424.  
  425.             $page_struct = array(
  426.                 "dateCreated"            => new IXR_Date($page_date),
  427.                 "userid"                => $page->post_author,
  428.                 "page_id"                => $page->ID,
  429.                 "page_status"            => $page->post_status,
  430.                 "description"            => $full_page["main"],
  431.                 "title"                    => $page->post_title,
  432.                 "link"                    => $link,
  433.                 "permaLink"                => $link,
  434.                 "categories"            => $categories,
  435.                 "excerpt"                => $page->post_excerpt,
  436.                 "text_more"                => $full_page["extended"],
  437.                 "mt_allow_comments"        => $allow_comments,
  438.                 "mt_allow_pings"        => $allow_pings,
  439.                 "wp_slug"                => $page->post_name,
  440.                 "wp_password"            => $page->post_password,
  441.                 "wp_author"                => $author->display_name,
  442.                 "wp_page_parent_id"        => $page->post_parent,
  443.                 "wp_page_parent_title"    => $parent_title,
  444.                 "wp_page_order"            => $page->menu_order,
  445.                 "wp_author_id"            => $author->ID,
  446.                 "wp_author_display_name"    => $author->display_name,
  447.                 "date_created_gmt"        => new IXR_Date($page_date_gmt),
  448.                 "custom_fields"            => $this->get_custom_fields($page_id),
  449.                 "wp_page_template"        => $page_template
  450.             );
  451.  
  452.             return($page_struct);
  453.         }
  454.         // If the page doesn't exist indicate that.
  455.         else {
  456.             return(new IXR_Error(404, __("Sorry, no such page.")));
  457.         }
  458.     }
  459.  
  460.     /**
  461.      * WordPress XML-RPC API
  462.       * wp_getPages
  463.      */
  464.     function wp_getPages($args) {
  465.         $this->escape($args);
  466.  
  467.         $blog_id    = (int) $args[0];
  468.         $username    = $args[1];
  469.         $password    = $args[2];
  470.  
  471.         if(!$this->login_pass_ok($username, $password)) {
  472.             return($this->error);
  473.         }
  474.  
  475.         set_current_user( 0, $username );
  476.         if( !current_user_can( 'edit_pages' ) )
  477.             return new IXR_Error( 401, __( 'Sorry, you can not edit pages.' ) );
  478.  
  479.         do_action('xmlrpc_call', 'wp.getPages');
  480.  
  481.         // Lookup info on pages.
  482.         $pages = get_pages();
  483.         $num_pages = count($pages);
  484.  
  485.         // If we have pages, put together their info.
  486.         if($num_pages >= 1) {
  487.             $pages_struct = array();
  488.  
  489.             for($i = 0; $i < $num_pages; $i++) {
  490.                 $page = wp_xmlrpc_server::wp_getPage(array(
  491.                     $blog_id, $pages[$i]->ID, $username, $password
  492.                 ));
  493.                 $pages_struct[] = $page;
  494.             }
  495.  
  496.             return($pages_struct);
  497.         }
  498.         // If no pages were found return an error.
  499.         else {
  500.             return(array());
  501.         }
  502.     }
  503.  
  504.     /**
  505.      * WordPress XML-RPC API
  506.       * wp_newPage
  507.      */
  508.     function wp_newPage($args) {
  509.         // Items not escaped here will be escaped in newPost.
  510.         $username    = $this->escape($args[1]);
  511.         $password    = $this->escape($args[2]);
  512.         $page        = $args[3];
  513.         $publish    = $args[4];
  514.  
  515.         if(!$this->login_pass_ok($username, $password)) {
  516.             return($this->error);
  517.         }
  518.  
  519.         do_action('xmlrpc_call', 'wp.newPage');
  520.  
  521.         // Set the user context and check if they are allowed
  522.         // to add new pages.
  523.         $user = set_current_user(0, $username);
  524.         if(!current_user_can("publish_pages")) {
  525.             return(new IXR_Error(401, __("Sorry, you can not add new pages.")));
  526.         }
  527.  
  528.         // Mark this as content for a page.
  529.         $args[3]["post_type"] = "page";
  530.  
  531.         // Let mw_newPost do all of the heavy lifting.
  532.         return($this->mw_newPost($args));
  533.     }
  534.  
  535.     /**
  536.      * WordPress XML-RPC API
  537.      * wp_deletePage
  538.      */
  539.     function wp_deletePage($args) {
  540.         $this->escape($args);
  541.  
  542.         $blog_id    = (int) $args[0];
  543.         $username    = $args[1];
  544.         $password    = $args[2];
  545.         $page_id    = (int) $args[3];
  546.  
  547.         if(!$this->login_pass_ok($username, $password)) {
  548.             return($this->error);
  549.         }
  550.  
  551.         do_action('xmlrpc_call', 'wp.deletePage');
  552.  
  553.         // Get the current page based on the page_id and
  554.         // make sure it is a page and not a post.
  555.         $actual_page = wp_get_single_post($page_id, ARRAY_A);
  556.         if(
  557.             !$actual_page
  558.             || ($actual_page["post_type"] != "page")
  559.         ) {
  560.             return(new IXR_Error(404, __("Sorry, no such page.")));
  561.         }
  562.  
  563.         // Set the user context and make sure they can delete pages.
  564.         set_current_user(0, $username);
  565.         if(!current_user_can("delete_page", $page_id)) {
  566.             return(new IXR_Error(401, __("Sorry, you do not have the right to delete this page.")));
  567.         }
  568.  
  569.         // Attempt to delete the page.
  570.         $result = wp_delete_post($page_id);
  571.         if(!$result) {
  572.             return(new IXR_Error(500, __("Failed to delete the page.")));
  573.         }
  574.  
  575.         return(true);
  576.     }
  577.  
  578.     /**
  579.      * WordPress XML-RPC API
  580.      * wp_editPage
  581.      */
  582.     function wp_editPage($args) {
  583.         // Items not escaped here will be escaped in editPost.
  584.         $blog_id    = (int) $args[0];
  585.         $page_id    = (int) $this->escape($args[1]);
  586.         $username    = $this->escape($args[2]);
  587.         $password    = $this->escape($args[3]);
  588.         $content    = $args[4];
  589.         $publish    = $args[5];
  590.  
  591.         if(!$this->login_pass_ok($username, $password)) {
  592.             return($this->error);
  593.         }
  594.  
  595.         do_action('xmlrpc_call', 'wp.editPage');
  596.  
  597.         // Get the page data and make sure it is a page.
  598.         $actual_page = wp_get_single_post($page_id, ARRAY_A);
  599.         if(
  600.             !$actual_page
  601.             || ($actual_page["post_type"] != "page")
  602.         ) {
  603.             return(new IXR_Error(404, __("Sorry, no such page.")));
  604.         }
  605.  
  606.         // Set the user context and make sure they are allowed to edit pages.
  607.         set_current_user(0, $username);
  608.         if(!current_user_can("edit_page", $page_id)) {
  609.             return(new IXR_Error(401, __("Sorry, you do not have the right to edit this page.")));
  610.         }
  611.  
  612.         // Mark this as content for a page.
  613.         $content["post_type"] = "page";
  614.  
  615.         // Arrange args in the way mw_editPost understands.
  616.         $args = array(
  617.             $page_id,
  618.             $username,
  619.             $password,
  620.             $content,
  621.             $publish
  622.         );
  623.  
  624.         // Let mw_editPost do all of the heavy lifting.
  625.         return($this->mw_editPost($args));
  626.     }
  627.  
  628.     /**
  629.      * WordPress XML-RPC API
  630.      * wp_getPageList
  631.      */
  632.     function wp_getPageList($args) {
  633.         global $wpdb;
  634.  
  635.         $this->escape($args);
  636.  
  637.         $blog_id                = (int) $args[0];
  638.         $username                = $args[1];
  639.         $password                = $args[2];
  640.  
  641.         if(!$this->login_pass_ok($username, $password)) {
  642.             return($this->error);
  643.         }
  644.  
  645.         set_current_user( 0, $username );
  646.         if( !current_user_can( 'edit_pages' ) )
  647.             return new IXR_Error( 401, __( 'Sorry, you can not edit pages.' ) );
  648.  
  649.         do_action('xmlrpc_call', 'wp.getPageList');
  650.  
  651.         // Get list of pages ids and titles
  652.         $page_list = $wpdb->get_results("
  653.             SELECT ID page_id,
  654.                 post_title page_title,
  655.                 post_parent page_parent_id,
  656.                 post_date_gmt,
  657.                 post_date
  658.             FROM {$wpdb->posts}
  659.             WHERE post_type = 'page'
  660.             ORDER BY ID
  661.         ");
  662.  
  663.         // The date needs to be formated properly.
  664.         $num_pages = count($page_list);
  665.         for($i = 0; $i < $num_pages; $i++) {
  666.             $post_date = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date);
  667.             $post_date_gmt = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date_gmt);
  668.  
  669.             $page_list[$i]->dateCreated = new IXR_Date($post_date);
  670.             $page_list[$i]->date_created_gmt = new IXR_Date($post_date_gmt);
  671.  
  672.             unset($page_list[$i]->post_date_gmt);
  673.             unset($page_list[$i]->post_date);
  674.         }
  675.  
  676.         return($page_list);
  677.     }
  678.  
  679.     /**
  680.      * WordPress XML-RPC API
  681.      * wp_getAuthors
  682.      */
  683.     function wp_getAuthors($args) {
  684.  
  685.         $this->escape($args);
  686.  
  687.         $blog_id    = (int) $args[0];
  688.         $username    = $args[1];
  689.         $password    = $args[2];
  690.  
  691.         if(!$this->login_pass_ok($username, $password)) {
  692.             return($this->error);
  693.         }
  694.  
  695.         set_current_user(0, $username);
  696.         if(!current_user_can("edit_posts")) {
  697.             return(new IXR_Error(401, __("Sorry, you can not edit posts on this blog.")));
  698.         }
  699.  
  700.         do_action('xmlrpc_call', 'wp.getAuthors');
  701.  
  702.         $authors = array();
  703.         foreach( (array) get_users_of_blog() as $row ) {
  704.             $authors[] = array(
  705.                 "user_id"       => $row->user_id,
  706.                 "user_login"    => $row->user_login,
  707.                 "display_name"  => $row->display_name
  708.             );
  709.         }
  710.  
  711.         return($authors);
  712.     }
  713.  
  714.     /**
  715.      * WordPress XML-RPC API
  716.      * wp_newCategory
  717.      */
  718.     function wp_newCategory($args) {
  719.         $this->escape($args);
  720.  
  721.         $blog_id                = (int) $args[0];
  722.         $username                = $args[1];
  723.         $password                = $args[2];
  724.         $category                = $args[3];
  725.  
  726.         if(!$this->login_pass_ok($username, $password)) {
  727.             return($this->error);
  728.         }
  729.  
  730.         do_action('xmlrpc_call', 'wp.newCategory');
  731.  
  732.         // Set the user context and make sure they are
  733.         // allowed to add a category.
  734.         set_current_user(0, $username);
  735.         if(!current_user_can("manage_categories")) {
  736.             return(new IXR_Error(401, __("Sorry, you do not have the right to add a category.")));
  737.         }
  738.  
  739.         // If no slug was provided make it empty so that
  740.         // WordPress will generate one.
  741.         if(empty($category["slug"])) {
  742.             $category["slug"] = "";
  743.         }
  744.  
  745.         // If no parent_id was provided make it empty
  746.         // so that it will be a top level page (no parent).
  747.         if ( !isset($category["parent_id"]) )
  748.             $category["parent_id"] = "";
  749.  
  750.         // If no description was provided make it empty.
  751.         if(empty($category["description"])) {
  752.             $category["description"] = "";
  753.         }
  754.  
  755.         $new_category = array(
  756.             "cat_name"                => $category["name"],
  757.             "category_nicename"        => $category["slug"],
  758.             "category_parent"        => $category["parent_id"],
  759.             "category_description"    => $category["description"]
  760.         );
  761.  
  762.         $cat_id = wp_insert_category($new_category);
  763.         if(!$cat_id) {
  764.             return(new IXR_Error(500, __("Sorry, the new category failed.")));
  765.         }
  766.  
  767.         return($cat_id);
  768.     }
  769.  
  770.     /**
  771.      * WordPress XML-RPC API
  772.      * wp_deleteCategory
  773.      */
  774.     function wp_deleteCategory($args) {
  775.         $this->escape($args);
  776.  
  777.         $blog_id        = (int) $args[0];
  778.         $username        = $args[1];
  779.         $password        = $args[2];
  780.         $category_id    = (int) $args[3];
  781.  
  782.         if( !$this->login_pass_ok( $username, $password ) ) {
  783.             return $this->error;
  784.         }
  785.  
  786.         do_action('xmlrpc_call', 'wp.deleteCategory');
  787.  
  788.         set_current_user(0, $username);
  789.         if( !current_user_can("manage_categories") ) {
  790.             return new IXR_Error( 401, __( "Sorry, you do not have the right to delete a category." ) );
  791.         }
  792.  
  793.         return wp_delete_category( $category_id );
  794.     }
  795.  
  796.  
  797.     /**
  798.      * WordPress XML-RPC API
  799.      * wp_suggestCategories
  800.      */
  801.     function wp_suggestCategories($args) {
  802.         $this->escape($args);
  803.  
  804.         $blog_id                = (int) $args[0];
  805.         $username                = $args[1];
  806.         $password                = $args[2];
  807.         $category                = $args[3];
  808.         $max_results            = (int) $args[4];
  809.  
  810.         if(!$this->login_pass_ok($username, $password)) {
  811.             return($this->error);
  812.         }
  813.  
  814.         set_current_user(0, $username);
  815.         if( !current_user_can( 'edit_posts' ) )
  816.             return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts to this blog in order to view categories.' ) );
  817.  
  818.         do_action('xmlrpc_call', 'wp.suggestCategories');
  819.  
  820.         $category_suggestions = array();
  821.         $args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category);
  822.         foreach ( (array) get_categories($args) as $cat ) {
  823.             $category_suggestions[] = array(
  824.                 "category_id"    => $cat->cat_ID,
  825.                 "category_name"    => $cat->cat_name
  826.             );
  827.         }
  828.  
  829.         return($category_suggestions);
  830.     }
  831.  
  832.     function wp_getCommentCount( $args ) {
  833.         $this->escape($args);
  834.  
  835.         $blog_id    = (int) $args[0];
  836.         $username    = $args[1];
  837.         $password    = $args[2];
  838.         $post_id    = (int) $args[3];
  839.  
  840.         if( !$this->login_pass_ok( $username, $password ) ) {
  841.             return $this->error;
  842.         }
  843.  
  844.         set_current_user( 0, $username );
  845.         if( !current_user_can( 'edit_posts' ) ) {
  846.             return new IXR_Error( 403, __( 'You are not allowed access to details about comments.' ) );
  847.         }
  848.  
  849.         do_action('xmlrpc_call', 'wp.getCommentCount');
  850.  
  851.         $count = wp_count_comments( $post_id );
  852.         return array(
  853.             "approved" => $count->approved,
  854.             "awaiting_moderation" => $count->moderated,
  855.             "spam" => $count->spam,
  856.             "total_comments" => $count->total_comments
  857.         );
  858.     }
  859.  
  860.  
  861.     function wp_getPostStatusList( $args ) {
  862.         $this->escape( $args );
  863.  
  864.         $blog_id    = (int) $args[0];
  865.         $username    = $args[1];
  866.         $password    = $args[2];
  867.  
  868.         if( !$this->login_pass_ok( $username, $password ) ) {
  869.             return $this->error;
  870.         }
  871.  
  872.         set_current_user( 0, $username );
  873.         if( !current_user_can( 'edit_posts' ) ) {
  874.             return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) );
  875.         }
  876.  
  877.         do_action('xmlrpc_call', 'wp.getPostStatusList');
  878.  
  879.         return get_post_statuses( );
  880.     }
  881.  
  882.  
  883.     function wp_getPageStatusList( $args ) {
  884.         $this->escape( $args );
  885.  
  886.         $blog_id    = (int) $args[0];
  887.         $username    = $args[1];
  888.         $password    = $args[2];
  889.  
  890.         if( !$this->login_pass_ok( $username, $password ) ) {
  891.             return $this->error;
  892.         }
  893.  
  894.         set_current_user( 0, $username );
  895.         if( !current_user_can( 'edit_posts' ) ) {
  896.             return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) );
  897.         }
  898.  
  899.         do_action('xmlrpc_call', 'wp.getPageStatusList');
  900.  
  901.         return get_page_statuses( );
  902.     }
  903.  
  904.     function wp_getPageTemplates( $args ) {
  905.         $this->escape( $args );
  906.  
  907.         $blog_id    = (int) $args[0];
  908.         $username    = $args[1];
  909.         $password    = $args[2];
  910.  
  911.         if( !$this->login_pass_ok( $username, $password ) ) {
  912.             return $this->error;
  913.         }
  914.  
  915.         set_current_user( 0, $username );
  916.         if( !current_user_can( 'edit_pages' ) ) {
  917.             return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) );
  918.         }
  919.  
  920.         $templates = get_page_templates( );
  921.         $templates['Default'] = 'default';
  922.  
  923.         return $templates;
  924.     }
  925.  
  926.     function wp_getOptions( $args ) {
  927.         $this->escape( $args );
  928.  
  929.         $blog_id    = (int) $args[0];
  930.         $username    = $args[1];
  931.         $password    = $args[2];
  932.         $options    = (array) $args[3];
  933.  
  934.         if( !$this->login_pass_ok( $username, $password ) )
  935.             return $this->error;
  936.  
  937.         $user = set_current_user( 0, $username );
  938.  
  939.         // If no specific options where asked for, return all of them
  940.         if (count( $options ) == 0 ) {
  941.             $options = array_keys($this->blog_options);
  942.         }
  943.  
  944.         return $this->_getOptions($options);
  945.     }
  946.  
  947.     function _getOptions($options)
  948.     {
  949.         $data = array( );
  950.         foreach( $options as $option ) {
  951.             if( array_key_exists( $option, $this->blog_options ) )
  952.             {
  953.                 $data[$option] = $this->blog_options[$option];
  954.                 //Is the value static or dynamic?
  955.                 if( isset( $data[$option]['option'] ) ) {
  956.                     $data[$option]['value'] = get_option( $data[$option]['option'] );
  957.                     unset($data[$option]['option']);
  958.                 }
  959.             }
  960.         }
  961.  
  962.         return $data;
  963.     }
  964.  
  965.     function wp_setOptions( $args ) {
  966.         $this->escape( $args );
  967.  
  968.         $blog_id    = (int) $args[0];
  969.         $username    = $args[1];
  970.         $password    = $args[2];
  971.         $options    = (array) $args[3];
  972.  
  973.         if( !$this->login_pass_ok( $username, $password ) )
  974.             return $this->error;
  975.  
  976.         $user = set_current_user( 0, $username );
  977.         if( !current_user_can( 'manage_options' ) )
  978.             return new IXR_Error( 403, __( 'You are not allowed to update options.' ) );
  979.  
  980.         foreach( $options as $o_name => $o_value ) {
  981.             $option_names[] = $o_name;
  982.             if( empty( $o_value ) )
  983.                 continue;
  984.  
  985.             if( !array_key_exists( $o_name, $this->blog_options ) )
  986.                 continue;
  987.  
  988.             if( $this->blog_options[$o_name]['readonly'] == true )
  989.                 continue;
  990.  
  991.             update_option( $this->blog_options[$o_name]['option'], $o_value );
  992.         }
  993.  
  994.         //Now return the updated values
  995.         return $this->_getOptions($option_names);
  996.     }
  997.  
  998.     /* Blogger API functions
  999.      * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/
  1000.      */
  1001.  
  1002.  
  1003.     /* blogger.getUsersBlogs will make more sense once we support multiple blogs */
  1004.     function blogger_getUsersBlogs($args) {
  1005.  
  1006.         $this->escape($args);
  1007.  
  1008.         $user_login = $args[1];
  1009.         $user_pass  = $args[2];
  1010.  
  1011.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1012.             return $this->error;
  1013.         }
  1014.  
  1015.         do_action('xmlrpc_call', 'blogger.getUsersBlogs');
  1016.  
  1017.         set_current_user(0, $user_login);
  1018.         $is_admin = current_user_can('manage_options');
  1019.  
  1020.         $struct = array(
  1021.             'isAdmin'  => $is_admin,
  1022.             'url'      => get_option('home') . '/',
  1023.             'blogid'   => '1',
  1024.             'blogName' => get_option('blogname'),
  1025.             'xmlrpc'   => get_option('home') . '/xmlrpc.php',
  1026.         );
  1027.  
  1028.         return array($struct);
  1029.     }
  1030.  
  1031.  
  1032.     /* blogger.getUsersInfo gives your client some info about you, so you don't have to */
  1033.     function blogger_getUserInfo($args) {
  1034.  
  1035.         $this->escape($args);
  1036.  
  1037.         $user_login = $args[1];
  1038.         $user_pass  = $args[2];
  1039.  
  1040.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1041.             return $this->error;
  1042.         }
  1043.  
  1044.         set_current_user( 0, $user_login );
  1045.         if( !current_user_can( 'edit_posts' ) )
  1046.             return new IXR_Error( 401, __( 'Sorry, you do not have access to user data on this blog.' ) );
  1047.  
  1048.         do_action('xmlrpc_call', 'blogger.getUserInfo');
  1049.  
  1050.         $user_data = get_userdatabylogin($user_login);
  1051.  
  1052.         $struct = array(
  1053.             'nickname'  => $user_data->nickname,
  1054.             'userid'    => $user_data->ID,
  1055.             'url'       => $user_data->user_url,
  1056.             'lastname'  => $user_data->last_name,
  1057.             'firstname' => $user_data->first_name
  1058.         );
  1059.  
  1060.         return $struct;
  1061.     }
  1062.  
  1063.  
  1064.     /* blogger.getPost ...gets a post */
  1065.     function blogger_getPost($args) {
  1066.  
  1067.         $this->escape($args);
  1068.  
  1069.         $post_ID    = (int) $args[1];
  1070.         $user_login = $args[2];
  1071.         $user_pass  = $args[3];
  1072.  
  1073.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1074.             return $this->error;
  1075.         }
  1076.  
  1077.         set_current_user( 0, $user_login );
  1078.         if( !current_user_can( 'edit_post', $post_ID ) )
  1079.             return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) );
  1080.  
  1081.         do_action('xmlrpc_call', 'blogger.getPost');
  1082.  
  1083.         $post_data = wp_get_single_post($post_ID, ARRAY_A);
  1084.  
  1085.         $categories = implode(',', wp_get_post_categories($post_ID));
  1086.  
  1087.         $content  = '<title>'.stripslashes($post_data['post_title']).'</title>';
  1088.         $content .= '<category>'.$categories.'</category>';
  1089.         $content .= stripslashes($post_data['post_content']);
  1090.  
  1091.         $struct = array(
  1092.             'userid'    => $post_data['post_author'],
  1093.             'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'])),
  1094.             'content'     => $content,
  1095.             'postid'  => $post_data['ID']
  1096.         );
  1097.  
  1098.         return $struct;
  1099.     }
  1100.  
  1101.  
  1102.     /* blogger.getRecentPosts ...gets recent posts */
  1103.     function blogger_getRecentPosts($args) {
  1104.  
  1105.         $this->escape($args);
  1106.  
  1107.         $blog_ID    = (int) $args[1]; /* though we don't use it yet */
  1108.         $user_login = $args[2];
  1109.         $user_pass  = $args[3];
  1110.         $num_posts  = $args[4];
  1111.  
  1112.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1113.             return $this->error;
  1114.         }
  1115.  
  1116.         do_action('xmlrpc_call', 'blogger.getRecentPosts');
  1117.  
  1118.         $posts_list = wp_get_recent_posts($num_posts);
  1119.  
  1120.         set_current_user( 0, $user_login );
  1121.  
  1122.         if (!$posts_list) {
  1123.             $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
  1124.             return $this->error;
  1125.         }
  1126.  
  1127.         foreach ($posts_list as $entry) {
  1128.             if( !current_user_can( 'edit_post', $entry['ID'] ) )
  1129.                 continue;
  1130.  
  1131.             $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']);
  1132.             $categories = implode(',', wp_get_post_categories($entry['ID']));
  1133.  
  1134.             $content  = '<title>'.stripslashes($entry['post_title']).'</title>';
  1135.             $content .= '<category>'.$categories.'</category>';
  1136.             $content .= stripslashes($entry['post_content']);
  1137.  
  1138.             $struct[] = array(
  1139.                 'userid' => $entry['post_author'],
  1140.                 'dateCreated' => new IXR_Date($post_date),
  1141.                 'content' => $content,
  1142.                 'postid' => $entry['ID'],
  1143.             );
  1144.  
  1145.         }
  1146.  
  1147.         $recent_posts = array();
  1148.         for ($j=0; $j<count($struct); $j++) {
  1149.             array_push($recent_posts, $struct[$j]);
  1150.         }
  1151.  
  1152.         return $recent_posts;
  1153.     }
  1154.  
  1155.  
  1156.     /* blogger.getTemplate returns your blog_filename */
  1157.     function blogger_getTemplate($args) {
  1158.  
  1159.         $this->escape($args);
  1160.  
  1161.       $blog_ID    = (int) $args[1];
  1162.       $user_login = $args[2];
  1163.       $user_pass  = $args[3];
  1164.       $template   = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */
  1165.  
  1166.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  1167.         return $this->error;
  1168.       }
  1169.  
  1170.       do_action('xmlrpc_call', 'blogger.getTemplate');
  1171.  
  1172.       set_current_user(0, $user_login);
  1173.       if ( !current_user_can('edit_themes') ) {
  1174.         return new IXR_Error(401, __('Sorry, this user can not edit the template.'));
  1175.       }
  1176.  
  1177.       /* warning: here we make the assumption that the blog's URL is on the same server */
  1178.       $filename = get_option('home') . '/';
  1179.       $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
  1180.  
  1181.       $f = fopen($filename, 'r');
  1182.       $content = fread($f, filesize($filename));
  1183.       fclose($f);
  1184.  
  1185.       /* so it is actually editable with a windows/mac client */
  1186.       // 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);
  1187.  
  1188.       return $content;
  1189.     }
  1190.  
  1191.  
  1192.     /* blogger.setTemplate updates the content of blog_filename */
  1193.     function blogger_setTemplate($args) {
  1194.  
  1195.         $this->escape($args);
  1196.  
  1197.         $blog_ID    = (int) $args[1];
  1198.         $user_login = $args[2];
  1199.         $user_pass  = $args[3];
  1200.         $content    = $args[4];
  1201.         $template   = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */
  1202.  
  1203.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1204.             return $this->error;
  1205.         }
  1206.  
  1207.         do_action('xmlrpc_call', 'blogger.setTemplate');
  1208.  
  1209.         set_current_user(0, $user_login);
  1210.         if ( !current_user_can('edit_themes') ) {
  1211.             return new IXR_Error(401, __('Sorry, this user can not edit the template.'));
  1212.         }
  1213.  
  1214.         /* warning: here we make the assumption that the blog's URL is on the same server */
  1215.         $filename = get_option('home') . '/';
  1216.         $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
  1217.  
  1218.         if ($f = fopen($filename, 'w+')) {
  1219.             fwrite($f, $content);
  1220.             fclose($f);
  1221.         } else {
  1222.             return new IXR_Error(500, __('Either the file is not writable, or something wrong happened. The file has not been updated.'));
  1223.         }
  1224.  
  1225.         return true;
  1226.     }
  1227.  
  1228.  
  1229.     /* blogger.newPost ...creates a new post */
  1230.     function blogger_newPost($args) {
  1231.  
  1232.         $this->escape($args);
  1233.  
  1234.         $blog_ID    = (int) $args[1]; /* though we don't use it yet */
  1235.         $user_login = $args[2];
  1236.         $user_pass  = $args[3];
  1237.         $content    = $args[4];
  1238.         $publish    = $args[5];
  1239.  
  1240.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1241.             return $this->error;
  1242.         }
  1243.  
  1244.         do_action('xmlrpc_call', 'blogger.newPost');
  1245.  
  1246.         $cap = ($publish) ? 'publish_posts' : 'edit_posts';
  1247.         $user = set_current_user(0, $user_login);
  1248.         if ( !current_user_can($cap) )
  1249.             return new IXR_Error(401, __('Sorry, you are not allowed to post on this blog.'));
  1250.  
  1251.         $post_status = ($publish) ? 'publish' : 'draft';
  1252.  
  1253.         $post_author = $user->ID;
  1254.  
  1255.         $post_title = xmlrpc_getposttitle($content);
  1256.         $post_category = xmlrpc_getpostcategory($content);
  1257.         $post_content = xmlrpc_removepostdata($content);
  1258.  
  1259.         $post_date = current_time('mysql');
  1260.         $post_date_gmt = current_time('mysql', 1);
  1261.  
  1262.         $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status');
  1263.  
  1264.         $post_ID = wp_insert_post($post_data);
  1265.         if ( is_wp_error( $post_ID ) )
  1266.             return new IXR_Error(500, $post_ID->get_error_message());
  1267.  
  1268.         if (!$post_ID)
  1269.             return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
  1270.  
  1271.         $this->attach_uploads( $post_ID, $post_content );
  1272.  
  1273.         logIO('O', "Posted ! ID: $post_ID");
  1274.  
  1275.         return $post_ID;
  1276.     }
  1277.  
  1278.     /* blogger.editPost ...edits a post */
  1279.     function blogger_editPost($args) {
  1280.  
  1281.         $this->escape($args);
  1282.  
  1283.         $post_ID     = (int) $args[1];
  1284.         $user_login  = $args[2];
  1285.         $user_pass   = $args[3];
  1286.         $content     = $args[4];
  1287.         $publish     = $args[5];
  1288.  
  1289.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1290.             return $this->error;
  1291.         }
  1292.  
  1293.         do_action('xmlrpc_call', 'blogger.editPost');
  1294.  
  1295.         $actual_post = wp_get_single_post($post_ID,ARRAY_A);
  1296.  
  1297.         if (!$actual_post) {
  1298.             return new IXR_Error(404, __('Sorry, no such post.'));
  1299.         }
  1300.  
  1301.         $this->escape($actual_post);
  1302.  
  1303.         set_current_user(0, $user_login);
  1304.         if ( !current_user_can('edit_post', $post_ID) )
  1305.             return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.'));
  1306.  
  1307.         extract($actual_post, EXTR_SKIP);
  1308.  
  1309.         if ( ('publish' == $post_status) && !current_user_can('publish_posts') )
  1310.             return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
  1311.  
  1312.         $post_title = xmlrpc_getposttitle($content);
  1313.         $post_category = xmlrpc_getpostcategory($content);
  1314.         $post_content = xmlrpc_removepostdata($content);
  1315.  
  1316.         $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
  1317.  
  1318.         $result = wp_update_post($postdata);
  1319.  
  1320.         if (!$result) {
  1321.             return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.'));
  1322.         }
  1323.         $this->attach_uploads( $ID, $post_content );
  1324.  
  1325.         return true;
  1326.     }
  1327.  
  1328.  
  1329.     /* blogger.deletePost ...deletes a post */
  1330.     function blogger_deletePost($args) {
  1331.         $this->escape($args);
  1332.  
  1333.         $post_ID     = (int) $args[1];
  1334.         $user_login  = $args[2];
  1335.         $user_pass   = $args[3];
  1336.         $publish     = $args[4];
  1337.  
  1338.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1339.             return $this->error;
  1340.         }
  1341.  
  1342.         do_action('xmlrpc_call', 'blogger.deletePost');
  1343.  
  1344.         $actual_post = wp_get_single_post($post_ID,ARRAY_A);
  1345.  
  1346.         if (!$actual_post) {
  1347.             return new IXR_Error(404, __('Sorry, no such post.'));
  1348.         }
  1349.  
  1350.         set_current_user(0, $user_login);
  1351.         if ( !current_user_can('edit_post', $post_ID) )
  1352.             return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.'));
  1353.  
  1354.         $result = wp_delete_post($post_ID);
  1355.  
  1356.         if (!$result) {
  1357.             return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.'));
  1358.         }
  1359.  
  1360.         return true;
  1361.     }
  1362.  
  1363.  
  1364.  
  1365.     /* MetaWeblog API functions
  1366.      * specs on wherever Dave Winer wants them to be
  1367.      */
  1368.  
  1369.     /* metaweblog.newPost creates a post */
  1370.     function mw_newPost($args) {
  1371.         $this->escape($args);
  1372.  
  1373.         $blog_ID     = (int) $args[0]; // we will support this in the near future
  1374.         $user_login  = $args[1];
  1375.         $user_pass   = $args[2];
  1376.         $content_struct = $args[3];
  1377.         $publish     = $args[4];
  1378.  
  1379.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1380.             return $this->error;
  1381.         }
  1382.         $user = set_current_user(0, $user_login);
  1383.  
  1384.         do_action('xmlrpc_call', 'metaWeblog.newPost');
  1385.  
  1386.         $cap = ( $publish ) ? 'publish_posts' : 'edit_posts';
  1387.         $error_message = __( 'Sorry, you are not allowed to publish posts on this blog.' );
  1388.         $post_type = 'post';
  1389.         $page_template = '';
  1390.         if( !empty( $content_struct['post_type'] ) ) {
  1391.             if( $content_struct['post_type'] == 'page' ) {
  1392.                 $cap = ( $publish ) ? 'publish_pages' : 'edit_pages';
  1393.                 $error_message = __( 'Sorry, you are not allowed to publish pages on this blog.' );
  1394.                 $post_type = 'page';
  1395.                 if( !empty( $content_struct['wp_page_template'] ) )
  1396.                     $page_template = $content_struct['wp_page_template'];
  1397.             }
  1398.             elseif( $content_struct['post_type'] == 'post' ) {
  1399.                 // This is the default, no changes needed
  1400.             }
  1401.             else {
  1402.                 // No other post_type values are allowed here
  1403.                 return new IXR_Error( 401, __( 'Invalid post type.' ) );
  1404.             }
  1405.         }
  1406.  
  1407.         if( !current_user_can( $cap ) ) {
  1408.             return new IXR_Error( 401, $error_message );
  1409.         }
  1410.  
  1411.         // Let WordPress generate the post_name (slug) unless
  1412.         // one has been provided.
  1413.         $post_name = "";
  1414.         if(isset($content_struct["wp_slug"])) {
  1415.             $post_name = $content_struct["wp_slug"];
  1416.         }
  1417.  
  1418.         // Only use a password if one was given.
  1419.         if(isset($content_struct["wp_password"])) {
  1420.             $post_password = $content_struct["wp_password"];
  1421.         }
  1422.  
  1423.         // Only set a post parent if one was provided.
  1424.         if(isset($content_struct["wp_page_parent_id"])) {
  1425.             $post_parent = $content_struct["wp_page_parent_id"];
  1426.         }
  1427.  
  1428.         // Only set the menu_order if it was provided.
  1429.         if(isset($content_struct["wp_page_order"])) {
  1430.             $menu_order = $content_struct["wp_page_order"];
  1431.         }
  1432.  
  1433.         $post_author = $user->ID;
  1434.  
  1435.         // If an author id was provided then use it instead.
  1436.         if(
  1437.             isset($content_struct["wp_author_id"])
  1438.             && ($user->ID != $content_struct["wp_author_id"])
  1439.         ) {
  1440.             switch($post_type) {
  1441.                 case "post":
  1442.                     if(!current_user_can("edit_others_posts")) {
  1443.                         return(new IXR_Error(401, __("You are not allowed to post as this user")));
  1444.                     }
  1445.                     break;
  1446.                 case "page":
  1447.                     if(!current_user_can("edit_others_pages")) {
  1448.                         return(new IXR_Error(401, __("You are not allowed to create pages as this user")));
  1449.                     }
  1450.                     break;
  1451.                 default:
  1452.                     return(new IXR_Error(401, __("Invalid post type.")));
  1453.                     break;
  1454.             }
  1455.             $post_author = $content_struct["wp_author_id"];
  1456.         }
  1457.  
  1458.         $post_title = $content_struct['title'];
  1459.         $post_content = apply_filters( 'content_save_pre', $content_struct['description'] );
  1460.  
  1461.         $post_status = $publish ? 'publish' : 'draft';
  1462.  
  1463.         if( isset( $content_struct["{$post_type}_status"] ) ) {
  1464.             switch( $content_struct["{$post_type}_status"] ) {
  1465.                 case 'draft':
  1466.                 case 'private':
  1467.                 case 'publish':
  1468.                     $post_status = $content_struct["{$post_type}_status"];
  1469.                     break;
  1470.                 case 'pending':
  1471.                     // Pending is only valid for posts, not pages.
  1472.                     if( $post_type === 'post' ) {
  1473.                         $post_status = $content_struct["{$post_type}_status"];
  1474.                     }
  1475.                     break;
  1476.                 default:
  1477.                     $post_status = $publish ? 'publish' : 'draft';
  1478.                     break;
  1479.             }
  1480.         }
  1481.  
  1482.         $post_excerpt = $content_struct['mt_excerpt'];
  1483.         $post_more = $content_struct['mt_text_more'];
  1484.  
  1485.         $tags_input = $content_struct['mt_keywords'];
  1486.  
  1487.         if(isset($content_struct["mt_allow_comments"])) {
  1488.             if(!is_numeric($content_struct["mt_allow_comments"])) {
  1489.                 switch($content_struct["mt_allow_comments"]) {
  1490.                     case "closed":
  1491.                         $comment_status = "closed";
  1492.                         break;
  1493.                     case "open":
  1494.                         $comment_status = "open";
  1495.                         break;
  1496.                     default:
  1497.                         $comment_status = get_option("default_comment_status");
  1498.                         break;
  1499.                 }
  1500.             }
  1501.             else {
  1502.                 switch((int) $content_struct["mt_allow_comments"]) {
  1503.                     case 0:
  1504.                     case 2:
  1505.                         $comment_status = "closed";
  1506.                         break;
  1507.                     case 1:
  1508.                         $comment_status = "open";
  1509.                         break;
  1510.                     default:
  1511.                         $comment_status = get_option("default_comment_status");
  1512.                         break;
  1513.                 }
  1514.             }
  1515.         }
  1516.         else {
  1517.             $comment_status = get_option("default_comment_status");
  1518.         }
  1519.  
  1520.         if(isset($content_struct["mt_allow_pings"])) {
  1521.             if(!is_numeric($content_struct["mt_allow_pings"])) {
  1522.                 switch($content_struct['mt_allow_pings']) {
  1523.                     case "closed":
  1524.                         $ping_status = "closed";
  1525.                         break;
  1526.                     case "open":
  1527.                         $ping_status = "open";
  1528.                         break;
  1529.                     default:
  1530.                         $ping_status = get_option("default_ping_status");
  1531.                         break;
  1532.                 }
  1533.             }
  1534.             else {
  1535.                 switch((int) $content_struct["mt_allow_pings"]) {
  1536.                     case 0:
  1537.                         $ping_status = "closed";
  1538.                         break;
  1539.                     case 1:
  1540.                         $ping_status = "open";
  1541.                         break;
  1542.                     default:
  1543.                         $ping_status = get_option("default_ping_status");
  1544.                         break;
  1545.                 }
  1546.             }
  1547.         }
  1548.         else {
  1549.             $ping_status = get_option("default_ping_status");
  1550.         }
  1551.  
  1552.         if ($post_more) {
  1553.             $post_content = $post_content . "<!--more-->" . $post_more;
  1554.         }
  1555.  
  1556.         $to_ping = $content_struct['mt_tb_ping_urls'];
  1557.         if ( is_array($to_ping) )
  1558.             $to_ping = implode(' ', $to_ping);
  1559.  
  1560.         // Do some timestamp voodoo
  1561.         if ( !empty( $content_struct['date_created_gmt'] ) )
  1562.             $dateCreated = str_replace( 'Z', '', $content_struct['date_created_gmt']->getIso() ) . 'Z'; // We know this is supposed to be GMT, so we're going to slap that Z on there by force
  1563.         elseif ( !empty( $content_struct['dateCreated']) )
  1564.             $dateCreated = $content_struct['dateCreated']->getIso();
  1565.  
  1566.         if ( !empty( $dateCreated ) ) {
  1567.             $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
  1568.             $post_date_gmt = iso8601_to_datetime($dateCreated, GMT);
  1569.         } else {
  1570.             $post_date = current_time('mysql');
  1571.             $post_date_gmt = current_time('mysql', 1);
  1572.         }
  1573.  
  1574.         $catnames = $content_struct['categories'];
  1575.         logIO('O', 'Post cats: ' . var_export($catnames,true));
  1576.         $post_category = array();
  1577.  
  1578.         if (is_array($catnames)) {
  1579.             foreach ($catnames as $cat) {
  1580.                 $post_category[] = get_cat_ID($cat);
  1581.             }
  1582.         }
  1583.  
  1584.         // We've got all the data -- post it:
  1585.         $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', 'post_type', 'post_name', 'post_password', 'post_parent', 'menu_order', 'tags_input', 'page_template');
  1586.  
  1587.         $post_ID = wp_insert_post($postdata, true);
  1588.         if ( is_wp_error( $post_ID ) )
  1589.             return new IXR_Error(500, $post_ID->get_error_message());
  1590.  
  1591.         if (!$post_ID) {
  1592.             return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
  1593.         }
  1594.  
  1595.         if ( isset($content_struct['custom_fields']) ) {
  1596.             $this->set_custom_fields($post_ID, $content_struct['custom_fields']);
  1597.         }
  1598.  
  1599.         // Handle enclosures 
  1600.         $enclosure = $content_struct['enclosure']; 
  1601.         if( is_array( $enclosure ) && isset( $enclosure['url'] ) && isset( $enclosure['length'] ) && isset( $enclosure['type'] ) ) { 
  1602.             add_post_meta( $post_ID, 'enclosure', $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type'] );
  1603.         } 
  1604.  
  1605.         $this->attach_uploads( $post_ID, $post_content );
  1606.  
  1607.         logIO('O', "Posted ! ID: $post_ID");
  1608.  
  1609.         return strval($post_ID);
  1610.     }
  1611.  
  1612.     function attach_uploads( $post_ID, $post_content ) {
  1613.         global $wpdb;
  1614.  
  1615.         // find any unattached files
  1616.         $attachments = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts} WHERE post_parent = '-1' AND post_type = 'attachment'" );
  1617.         if( is_array( $attachments ) ) {
  1618.             foreach( $attachments as $file ) {
  1619.                 if( strpos( $post_content, $file->guid ) !== false ) {
  1620.                     $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_parent = %d WHERE ID = %d", $post_ID, $file->ID) );
  1621.                 }
  1622.             }
  1623.         }
  1624.     }
  1625.  
  1626.     /* metaweblog.editPost ...edits a post */
  1627.     function mw_editPost($args) {
  1628.  
  1629.         $this->escape($args);
  1630.  
  1631.         $post_ID     = (int) $args[0];
  1632.         $user_login  = $args[1];
  1633.         $user_pass   = $args[2];
  1634.         $content_struct = $args[3];
  1635.         $publish     = $args[4];
  1636.  
  1637.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1638.             return $this->error;
  1639.         }
  1640.         $user = set_current_user(0, $user_login);
  1641.  
  1642.         do_action('xmlrpc_call', 'metaWeblog.editPost');
  1643.  
  1644.         $cap = ( $publish ) ? 'publish_posts' : 'edit_posts';
  1645.         $error_message = __( 'Sorry, you are not allowed to publish posts on this blog.' );
  1646.         $post_type = 'post';
  1647.         $page_template = '';
  1648.         if( !empty( $content_struct['post_type'] ) ) {
  1649.             if( $content_struct['post_type'] == 'page' ) {
  1650.                 $cap = ( $publish ) ? 'publish_pages' : 'edit_pages';
  1651.                 $error_message = __( 'Sorry, you are not allowed to publish pages on this blog.' );
  1652.                 $post_type = 'page';
  1653.                 if( !empty( $content_struct['wp_page_template'] ) )
  1654.                     $page_template = $content_struct['wp_page_template'];
  1655.             }
  1656.             elseif( $content_struct['post_type'] == 'post' ) {
  1657.                 // This is the default, no changes needed
  1658.             }
  1659.             else {
  1660.                 // No other post_type values are allowed here
  1661.                 return new IXR_Error( 401, __( 'Invalid post type.' ) );
  1662.             }
  1663.         }
  1664.  
  1665.         if( !current_user_can( $cap ) ) {
  1666.             return new IXR_Error( 401, $error_message );
  1667.         }
  1668.  
  1669.         $postdata = wp_get_single_post($post_ID, ARRAY_A);
  1670.  
  1671.         // If there is no post data for the give post id, stop
  1672.         // now and return an error.  Other wise a new post will be
  1673.         // created (which was the old behavior).
  1674.         if(empty($postdata["ID"])) {
  1675.             return(new IXR_Error(404, __("Invalid post id.")));
  1676.         }
  1677.  
  1678.         $this->escape($postdata);
  1679.         extract($postdata, EXTR_SKIP);
  1680.  
  1681.         // Let WordPress manage slug if none was provided.
  1682.         $post_name = "";
  1683.         if(isset($content_struct["wp_slug"])) {
  1684.             $post_name = $content_struct["wp_slug"];
  1685.         }
  1686.  
  1687.         // Only use a password if one was given.
  1688.         if(isset($content_struct["wp_password"])) {
  1689.             $post_password = $content_struct["wp_password"];
  1690.         }
  1691.  
  1692.         // Only set a post parent if one was given.
  1693.         if(isset($content_struct["wp_page_parent_id"])) {
  1694.             $post_parent = $content_struct["wp_page_parent_id"];
  1695.         }
  1696.  
  1697.         // Only set the menu_order if it was given.
  1698.         if(isset($content_struct["wp_page_order"])) {
  1699.             $menu_order = $content_struct["wp_page_order"];
  1700.         }
  1701.  
  1702.         $post_author = $postdata["post_author"];
  1703.  
  1704.         // Only set the post_author if one is set.
  1705.         if(
  1706.             isset($content_struct["wp_author_id"])
  1707.             && ($user->ID != $content_struct["wp_author_id"])
  1708.         ) {
  1709.             switch($post_type) {
  1710.                 case "post":
  1711.                     if(!current_user_can("edit_others_posts")) {
  1712.                         return(new IXR_Error(401, __("You are not allowed to change the post author as this user.")));
  1713.                     }
  1714.                     break;
  1715.                 case "page":
  1716.                     if(!current_user_can("edit_others_pages")) {
  1717.                         return(new IXR_Error(401, __("You are not allowed to change the page author as this user.")));
  1718.                     }
  1719.                     break;
  1720.                 default:
  1721.                     return(new IXR_Error(401, __("Invalid post type.")));
  1722.                     break;
  1723.             }
  1724.             $post_author = $content_struct["wp_author_id"];
  1725.         }
  1726.  
  1727.         if(isset($content_struct["mt_allow_comments"])) {
  1728.             if(!is_numeric($content_struct["mt_allow_comments"])) {
  1729.                 switch($content_struct["mt_allow_comments"]) {
  1730.                     case "closed":
  1731.                         $comment_status = "closed";
  1732.                         break;
  1733.                     case "open":
  1734.                         $comment_status = "open";
  1735.                         break;
  1736.                     default:
  1737.                         $comment_status = get_option("default_comment_status");
  1738.                         break;
  1739.                 }
  1740.             }
  1741.             else {
  1742.                 switch((int) $content_struct["mt_allow_comments"]) {
  1743.                     case 0:
  1744.                     case 2:
  1745.                         $comment_status = "closed";
  1746.                         break;
  1747.                     case 1:
  1748.                         $comment_status = "open";
  1749.                         break;
  1750.                     default:
  1751.                         $comment_status = get_option("default_comment_status");
  1752.                         break;
  1753.                 }
  1754.             }
  1755.         }
  1756.  
  1757.         if(isset($content_struct["mt_allow_pings"])) {
  1758.             if(!is_numeric($content_struct["mt_allow_pings"])) {
  1759.                 switch($content_struct["mt_allow_pings"]) {
  1760.                     case "closed":
  1761.                         $ping_status = "closed";
  1762.                         break;
  1763.                     case "open":
  1764.                         $ping_status = "open";
  1765.                         break;
  1766.                     default:
  1767.                         $ping_status = get_option("default_ping_status");
  1768.                         break;
  1769.                 }
  1770.             }
  1771.             else {
  1772.                 switch((int) $content_struct["mt_allow_pings"]) {
  1773.                     case 0:
  1774.                         $ping_status = "closed";
  1775.                         break;
  1776.                     case 1:
  1777.                         $ping_status = "open";
  1778.                         break;
  1779.                     default:
  1780.                         $ping_status = get_option("default_ping_status");
  1781.                         break;
  1782.                 }
  1783.             }
  1784.         }
  1785.  
  1786.         $post_title = $content_struct['title'];
  1787.         $post_content = apply_filters( 'content_save_pre', $content_struct['description'] );
  1788.         $catnames = $content_struct['categories'];
  1789.  
  1790.         $post_category = array();
  1791.  
  1792.         if (is_array($catnames)) {
  1793.             foreach ($catnames as $cat) {
  1794.                  $post_category[] = get_cat_ID($cat);
  1795.             }
  1796.         }
  1797.  
  1798.         $post_excerpt = $content_struct['mt_excerpt'];
  1799.         $post_more = $content_struct['mt_text_more'];
  1800.  
  1801.         $post_status = $publish ? 'publish' : 'draft';
  1802.         if( isset( $content_struct["{$post_type}_status"] ) ) {
  1803.             switch( $content_struct["{$post_type}_status"] ) {
  1804.                 case 'draft':
  1805.                 case 'private':
  1806.                 case 'publish':
  1807.                     $post_status = $content_struct["{$post_type}_status"];
  1808.                     break;
  1809.                 case 'pending':
  1810.                     // Pending is only valid for posts, not pages.
  1811.                     if( $post_type === 'post' ) {
  1812.                         $post_status = $content_struct["{$post_type}_status"];
  1813.                     }
  1814.                     break;
  1815.                 default:
  1816.                     $post_status = $publish ? 'publish' : 'draft';
  1817.                     break;
  1818.             }
  1819.         }
  1820.  
  1821.         $tags_input = $content_struct['mt_keywords'];
  1822.  
  1823.         if ( ('publish' == $post_status) ) {
  1824.             if ( ( 'page' == $post_type ) && !current_user_can('publish_pages') )
  1825.                 return new IXR_Error(401, __('Sorry, you do not have the right to publish this page.'));
  1826.             else if ( !current_user_can('publish_posts') )
  1827.                 return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
  1828.         }
  1829.  
  1830.         if ($post_more) {
  1831.             $post_content = $post_content . "<!--more-->" . $post_more;
  1832.         }
  1833.  
  1834.         $to_ping = $content_struct['mt_tb_ping_urls'];
  1835.         if ( is_array($to_ping) )
  1836.             $to_ping = implode(' ', $to_ping);
  1837.  
  1838.         // Do some timestamp voodoo
  1839.         if ( !empty( $content_struct['date_created_gmt'] ) )
  1840.             $dateCreated = str_replace( 'Z', '', $content_struct['date_created_gmt']->getIso() ) . 'Z'; // We know this is supposed to be GMT, so we're going to slap that Z on there by force
  1841.         elseif ( !empty( $content_struct['dateCreated']) )
  1842.             $dateCreated = $content_struct['dateCreated']->getIso();
  1843.  
  1844.         if ( !empty( $dateCreated ) ) {
  1845.             $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
  1846.             $post_date_gmt = iso8601_to_datetime($dateCreated, GMT);
  1847.         } else {
  1848.             $post_date     = $postdata['post_date'];
  1849.             $post_date_gmt = $postdata['post_date_gmt'];
  1850.         }
  1851.  
  1852.         // We've got all the data -- post it:
  1853.         $newpost = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'comment_status', 'ping_status', 'post_date', 'post_date_gmt', 'to_ping', 'post_name', 'post_password', 'post_parent', 'menu_order', 'post_author', 'tags_input', 'page_template');
  1854.  
  1855.         $result = wp_update_post($newpost, true);
  1856.         if ( is_wp_error( $result ) )
  1857.             return new IXR_Error(500, $result->get_error_message());
  1858.  
  1859.         if (!$result) {
  1860.             return new IXR_Error(500, __('Sorry, your entry could not be edited. Something wrong happened.'));
  1861.         }
  1862.  
  1863.         if ( isset($content_struct['custom_fields']) ) {
  1864.             $this->set_custom_fields($post_ID, $content_struct['custom_fields']);
  1865.         }
  1866.  
  1867.         // Handle enclosures 
  1868.         $enclosure = $content_struct['enclosure']; 
  1869.         if( is_array( $enclosure ) && isset( $enclosure['url'] ) && isset( $enclosure['length'] ) && isset( $enclosure['type'] ) ) { 
  1870.             add_post_meta( $post_ID, 'enclosure', $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type'] );
  1871.         } 
  1872.  
  1873.         $this->attach_uploads( $ID, $post_content );
  1874.  
  1875.         logIO('O',"(MW) Edited ! ID: $post_ID");
  1876.  
  1877.         return true;
  1878.     }
  1879.  
  1880.  
  1881.     /* metaweblog.getPost ...returns a post */
  1882.     function mw_getPost($args) {
  1883.  
  1884.         $this->escape($args);
  1885.  
  1886.         $post_ID     = (int) $args[0];
  1887.         $user_login  = $args[1];
  1888.         $user_pass   = $args[2];
  1889.  
  1890.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1891.             return $this->error;
  1892.         }
  1893.  
  1894.         set_current_user( 0, $user_login );
  1895.         if( !current_user_can( 'edit_post', $post_ID ) )
  1896.             return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) );
  1897.  
  1898.         do_action('xmlrpc_call', 'metaWeblog.getPost');
  1899.  
  1900.         $postdata = wp_get_single_post($post_ID, ARRAY_A);
  1901.  
  1902.         if ($postdata['post_date'] != '') {
  1903.             $post_date = mysql2date('Ymd\TH:i:s', $postdata['post_date']);
  1904.             $post_date_gmt = mysql2date('Ymd\TH:i:s', $postdata['post_date_gmt']);
  1905.  
  1906.             $categories = array();
  1907.             $catids = wp_get_post_categories($post_ID);
  1908.             foreach($catids as $catid)
  1909.                 $categories[] = get_cat_name($catid);
  1910.  
  1911.             $tagnames = array();
  1912.             $tags = wp_get_post_tags( $post_ID );
  1913.             if ( !empty( $tags ) ) {
  1914.                 foreach ( $tags as $tag )
  1915.                     $tagnames[] = $tag->name;
  1916.                 $tagnames = implode( ', ', $tagnames );
  1917.             } else {
  1918.                 $tagnames = '';
  1919.             }
  1920.  
  1921.             $post = get_extended($postdata['post_content']);
  1922.             $link = post_permalink($postdata['ID']);
  1923.  
  1924.             // Get the author info.
  1925.             $author = get_userdata($postdata['post_author']);
  1926.  
  1927.             $allow_comments = ('open' == $postdata['comment_status']) ? 1 : 0;
  1928.             $allow_pings = ('open' == $postdata['ping_status']) ? 1 : 0;
  1929.  
  1930.             // Consider future posts as published
  1931.             if( $postdata['post_status'] === 'future' ) {
  1932.                 $postdata['post_status'] = 'publish';
  1933.             }
  1934.  
  1935.             $resp = array(
  1936.                 'dateCreated' => new IXR_Date($post_date),
  1937.                 'userid' => $postdata['post_author'],
  1938.                 'postid' => $postdata['ID'],
  1939.                 'description' => $post['main'],
  1940.                 'title' => $postdata['post_title'],
  1941.                 'link' => $link,
  1942.                 'permaLink' => $link,
  1943.                 // commented out because no other tool seems to use this
  1944.                 //          'content' => $entry['post_content'],
  1945.                 'categories' => $categories,
  1946.                 'mt_excerpt' => $postdata['post_excerpt'],
  1947.                 'mt_text_more' => $post['extended'],
  1948.                 'mt_allow_comments' => $allow_comments,
  1949.                 'mt_allow_pings' => $allow_pings,
  1950.                 'mt_keywords' => $tagnames,
  1951.                 'wp_slug' => $postdata['post_name'],
  1952.                 'wp_password' => $postdata['post_password'],
  1953.                 'wp_author_id' => $author->ID,
  1954.                 'wp_author_display_name'    => $author->display_name,
  1955.                 'date_created_gmt' => new IXR_Date($post_date_gmt),
  1956.                 'post_status' => $postdata['post_status'],
  1957.                 'custom_fields' => $this->get_custom_fields($post_ID)
  1958.             );
  1959.  
  1960.             return $resp;
  1961.         } else {
  1962.             return new IXR_Error(404, __('Sorry, no such post.'));
  1963.         }
  1964.     }
  1965.  
  1966.  
  1967.     /* metaweblog.getRecentPosts ...returns recent posts */
  1968.     function mw_getRecentPosts($args) {
  1969.  
  1970.         $this->escape($args);
  1971.  
  1972.         $blog_ID     = (int) $args[0];
  1973.         $user_login  = $args[1];
  1974.         $user_pass   = $args[2];
  1975.         $num_posts   = (int) $args[3];
  1976.  
  1977.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  1978.             return $this->error;
  1979.         }
  1980.  
  1981.         do_action('xmlrpc_call', 'metaWeblog.getRecentPosts');
  1982.  
  1983.         $posts_list = wp_get_recent_posts($num_posts);
  1984.  
  1985.         if (!$posts_list) {
  1986.             $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
  1987.             return $this->error;
  1988.         }
  1989.  
  1990.         set_current_user( 0, $user_login );
  1991.  
  1992.         foreach ($posts_list as $entry) {
  1993.             if( !current_user_can( 'edit_post', $entry['ID'] ) )
  1994.                 continue;
  1995.  
  1996.             $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']);
  1997.             $post_date_gmt = mysql2date('Ymd\TH:i:s', $entry['post_date_gmt']);
  1998.  
  1999.             $categories = array();
  2000.             $catids = wp_get_post_categories($entry['ID']);
  2001.             foreach($catids as $catid) {
  2002.                 $categories[] = get_cat_name($catid);
  2003.             }
  2004.  
  2005.             $tagnames = array();
  2006.             $tags = wp_get_post_tags( $entry['ID'] );
  2007.             if ( !empty( $tags ) ) {
  2008.                 foreach ( $tags as $tag ) {
  2009.                     $tagnames[] = $tag->name;
  2010.                 }
  2011.                 $tagnames = implode( ', ', $tagnames );
  2012.             } else {
  2013.                 $tagnames = '';
  2014.             }
  2015.  
  2016.             $post = get_extended($entry['post_content']);
  2017.             $link = post_permalink($entry['ID']);
  2018.  
  2019.             // Get the post author info.
  2020.             $author = get_userdata($entry['post_author']);
  2021.  
  2022.             $allow_comments = ('open' == $entry['comment_status']) ? 1 : 0;
  2023.             $allow_pings = ('open' == $entry['ping_status']) ? 1 : 0;
  2024.  
  2025.             // Consider future posts as published
  2026.             if( $entry['post_status'] === 'future' ) {
  2027.                 $entry['post_status'] = 'publish';
  2028.             }
  2029.  
  2030.             $struct[] = array(
  2031.                 'dateCreated' => new IXR_Date($post_date),
  2032.                 'userid' => $entry['post_author'],
  2033.                 'postid' => $entry['ID'],
  2034.                 'description' => $post['main'],
  2035.                 'title' => $entry['post_title'],
  2036.                 'link' => $link,
  2037.                 'permaLink' => $link,
  2038. // commented out because no other tool seems to use this
  2039. //          'content' => $entry['post_content'],
  2040.                 'categories' => $categories,
  2041.                 'mt_excerpt' => $entry['post_excerpt'],
  2042.                 'mt_text_more' => $post['extended'],
  2043.                 'mt_allow_comments' => $allow_comments,
  2044.                 'mt_allow_pings' => $allow_pings,
  2045.                 'mt_keywords' => $tagnames,
  2046.                 'wp_slug' => $entry['post_name'],
  2047.                 'wp_password' => $entry['post_password'],
  2048.                 'wp_author_id' => $author->ID,
  2049.                 'wp_author_display_name' => $author->display_name,
  2050.                 'date_created_gmt' => new IXR_Date($post_date_gmt),
  2051.                 'post_status' => $entry['post_status'],
  2052.                 'custom_fields' => $this->get_custom_fields($entry['ID'])
  2053.             );
  2054.  
  2055.         }
  2056.  
  2057.         $recent_posts = array();
  2058.         for ($j=0; $j<count($struct); $j++) {
  2059.             array_push($recent_posts, $struct[$j]);
  2060.         }
  2061.  
  2062.         return $recent_posts;
  2063.     }
  2064.  
  2065.  
  2066.     /* metaweblog.getCategories ...returns the list of categories on a given blog */
  2067.     function mw_getCategories($args) {
  2068.  
  2069.         $this->escape($args);
  2070.  
  2071.         $blog_ID     = (int) $args[0];
  2072.         $user_login  = $args[1];
  2073.         $user_pass   = $args[2];
  2074.  
  2075.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  2076.             return $this->error;
  2077.         }
  2078.  
  2079.         set_current_user( 0, $user_login );
  2080.         if( !current_user_can( 'edit_posts' ) )
  2081.             return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this blog in order to view categories.' ) );
  2082.  
  2083.         do_action('xmlrpc_call', 'metaWeblog.getCategories');
  2084.  
  2085.         $categories_struct = array();
  2086.  
  2087.         if ( $cats = get_categories('get=all') ) {
  2088.             foreach ( $cats as $cat ) {
  2089.                 $struct['categoryId'] = $cat->term_id;
  2090.                 $struct['parentId'] = $cat->parent;
  2091.                 $struct['description'] = $cat->name;
  2092.                 $struct['categoryName'] = $cat->name;
  2093.                 $struct['htmlUrl'] = wp_specialchars(get_category_link($cat->term_id));
  2094.                 $struct['rssUrl'] = wp_specialchars(get_category_rss_link(false, $cat->term_id, $cat->name));
  2095.  
  2096.                 $categories_struct[] = $struct;
  2097.             }
  2098.         }
  2099.  
  2100.         return $categories_struct;
  2101.     }
  2102.  
  2103.  
  2104.     /* metaweblog.newMediaObject uploads a file, following your settings */
  2105.     function mw_newMediaObject($args) {
  2106.         // adapted from a patch by Johann Richard
  2107.         // http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/
  2108.  
  2109.         global $wpdb;
  2110.  
  2111.         $blog_ID     = (int) $args[0];
  2112.         $user_login  = $wpdb->escape($args[1]);
  2113.         $user_pass   = $wpdb->escape($args[2]);
  2114.         $data        = $args[3];
  2115.  
  2116.         $name = sanitize_file_name( $data['name'] );
  2117.         $type = $data['type'];
  2118.         $bits = $data['bits'];
  2119.  
  2120.         logIO('O', '(MW) Received '.strlen($bits).' bytes');
  2121.  
  2122.         if ( !$this->login_pass_ok($user_login, $user_pass) )
  2123.             return $this->error;
  2124.  
  2125.         do_action('xmlrpc_call', 'metaWeblog.newMediaObject');
  2126.  
  2127.         set_current_user(0, $user_login);
  2128.         if ( !current_user_can('upload_files') ) {
  2129.             logIO('O', '(MW) User does not have upload_files capability');
  2130.             $this->error = new IXR_Error(401, __('You are not allowed to upload files to this site.'));
  2131.             return $this->error;
  2132.         }
  2133.  
  2134.         if ( $upload_err = apply_filters( "pre_upload_error", false ) )
  2135.             return new IXR_Error(500, $upload_err);
  2136.  
  2137.         if(!empty($data["overwrite"]) && ($data["overwrite"] == true)) {
  2138.             // Get postmeta info on the object.
  2139.             $old_file = $wpdb->get_row("
  2140.                 SELECT ID
  2141.                 FROM {$wpdb->posts}
  2142.                 WHERE post_title = '{$name}'
  2143.                     AND post_type = 'attachment'
  2144.             ");
  2145.  
  2146.             // Delete previous file.
  2147.             wp_delete_attachment($old_file->ID);
  2148.  
  2149.             // Make sure the new name is different by pre-pending the
  2150.             // previous post id.
  2151.             $filename = preg_replace("/^wpid\d+-/", "", $name);
  2152.             $name = "wpid{$old_file->ID}-{$filename}";
  2153.         }
  2154.  
  2155.         $upload = wp_upload_bits($name, $type, $bits);
  2156.         if ( ! empty($upload['error']) ) {
  2157.             $errorString = sprintf(__('Could not write file %1$s (%2$s)'), $name, $upload['error']);
  2158.             logIO('O', '(MW) ' . $errorString);
  2159.             return new IXR_Error(500, $errorString);
  2160.         }
  2161.         // Construct the attachment array
  2162.         // attach to post_id -1
  2163.         $post_id = -1;
  2164.         $attachment = array(
  2165.             'post_title' => $name,
  2166.             'post_content' => '',
  2167.             'post_type' => 'attachment',
  2168.             'post_parent' => $post_id,
  2169.             'post_mime_type' => $type,
  2170.             'guid' => $upload[ 'url' ]
  2171.         );
  2172.  
  2173.         // Save the data
  2174.         $id = wp_insert_attachment( $attachment, $upload[ 'file' ], $post_id );
  2175.         wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );
  2176.  
  2177.         return apply_filters( 'wp_handle_upload', array( 'file' => $name, 'url' => $upload[ 'url' ], 'type' => $type ) );
  2178.     }
  2179.  
  2180.  
  2181.     /* MovableType API functions
  2182.      * specs on http://www.movabletype.org/docs/mtmanual_programmatic.html
  2183.      */
  2184.  
  2185.     /* mt.getRecentPostTitles ...returns recent posts' titles */
  2186.     function mt_getRecentPostTitles($args) {
  2187.  
  2188.         $this->escape($args);
  2189.  
  2190.         $blog_ID     = (int) $args[0];
  2191.         $user_login  = $args[1];
  2192.         $user_pass   = $args[2];
  2193.         $num_posts   = (int) $args[3];
  2194.  
  2195.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  2196.             return $this->error;
  2197.         }
  2198.  
  2199.         do_action('xmlrpc_call', 'mt.getRecentPostTitles');
  2200.  
  2201.         $posts_list = wp_get_recent_posts($num_posts);
  2202.  
  2203.         if (!$posts_list) {
  2204.             $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
  2205.             return $this->error;
  2206.         }
  2207.  
  2208.         set_current_user( 0, $user_login );
  2209.  
  2210.         foreach ($posts_list as $entry) {
  2211.             if( !current_user_can( 'edit_post', $entry['ID'] ) )
  2212.                 continue;
  2213.  
  2214.             $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']);
  2215.             $post_date_gmt = mysql2date('Ymd\TH:i:s', $entry['post_date_gmt']);
  2216.  
  2217.             $struct[] = array(
  2218.                 'dateCreated' => new IXR_Date($post_date),
  2219.                 'userid' => $entry['post_author'],
  2220.                 'postid' => $entry['ID'],
  2221.                 'title' => $entry['post_title'],
  2222.                 'date_created_gmt' => new IXR_Date($post_date_gmt)
  2223.             );
  2224.  
  2225.         }
  2226.  
  2227.         $recent_posts = array();
  2228.         for ($j=0; $j<count($struct); $j++) {
  2229.             array_push($recent_posts, $struct[$j]);
  2230.         }
  2231.  
  2232.         return $recent_posts;
  2233.     }
  2234.  
  2235.  
  2236.     /* mt.getCategoryList ...returns the list of categories on a given blog */
  2237.     function mt_getCategoryList($args) {
  2238.  
  2239.         $this->escape($args);
  2240.  
  2241.         $blog_ID     = (int) $args[0];
  2242.         $user_login  = $args[1];
  2243.         $user_pass   = $args[2];
  2244.  
  2245.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  2246.             return $this->error;
  2247.         }
  2248.  
  2249.         set_current_user( 0, $user_login );
  2250.         if( !current_user_can( 'edit_posts' ) )
  2251.             return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this blog in order to view categories.' ) );
  2252.  
  2253.         do_action('xmlrpc_call', 'mt.getCategoryList');
  2254.  
  2255.         $categories_struct = array();
  2256.  
  2257.         if ( $cats = get_categories('hide_empty=0&hierarchical=0') ) {
  2258.             foreach ($cats as $cat) {
  2259.                 $struct['categoryId'] = $cat->term_id;
  2260.                 $struct['categoryName'] = $cat->name;
  2261.  
  2262.                 $categories_struct[] = $struct;
  2263.             }
  2264.         }
  2265.  
  2266.         return $categories_struct;
  2267.     }
  2268.  
  2269.  
  2270.     /* mt.getPostCategories ...returns a post's categories */
  2271.     function mt_getPostCategories($args) {
  2272.  
  2273.         $this->escape($args);
  2274.  
  2275.         $post_ID     = (int) $args[0];
  2276.         $user_login  = $args[1];
  2277.         $user_pass   = $args[2];
  2278.  
  2279.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  2280.             return $this->error;
  2281.         }
  2282.  
  2283.         set_current_user( 0, $user_login );
  2284.         if( !current_user_can( 'edit_post', $post_ID ) )
  2285.             return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) );
  2286.  
  2287.         do_action('xmlrpc_call', 'mt.getPostCategories');
  2288.  
  2289.         $categories = array();
  2290.         $catids = wp_get_post_categories(intval($post_ID));
  2291.         // first listed category will be the primary category
  2292.         $isPrimary = true;
  2293.         foreach($catids as $catid) {
  2294.             $categories[] = array(
  2295.                 'categoryName' => get_cat_name($catid),
  2296.                 'categoryId' => (string) $catid,
  2297.                 'isPrimary' => $isPrimary
  2298.             );
  2299.             $isPrimary = false;
  2300.         }
  2301.  
  2302.         return $categories;
  2303.     }
  2304.  
  2305.  
  2306.     /* mt.setPostCategories ...sets a post's categories */
  2307.     function mt_setPostCategories($args) {
  2308.  
  2309.         $this->escape($args);
  2310.  
  2311.         $post_ID     = (int) $args[0];
  2312.         $user_login  = $args[1];
  2313.         $user_pass   = $args[2];
  2314.         $categories  = $args[3];
  2315.  
  2316.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  2317.             return $this->error;
  2318.         }
  2319.  
  2320.         do_action('xmlrpc_call', 'mt.setPostCategories');
  2321.  
  2322.         set_current_user(0, $user_login);
  2323.         if ( !current_user_can('edit_post', $post_ID) )
  2324.             return new IXR_Error(401, __('Sorry, you can not edit this post.'));
  2325.  
  2326.         foreach($categories as $cat) {
  2327.             $catids[] = $cat['categoryId'];
  2328.         }
  2329.  
  2330.         wp_set_post_categories($post_ID, $catids);
  2331.  
  2332.         return true;
  2333.     }
  2334.  
  2335.  
  2336.     /* mt.supportedMethods ...returns an array of methods supported by this server */
  2337.     function mt_supportedMethods($args) {
  2338.  
  2339.         do_action('xmlrpc_call', 'mt.supportedMethods');
  2340.  
  2341.         $supported_methods = array();
  2342.         foreach($this->methods as $key=>$value) {
  2343.             $supported_methods[] = $key;
  2344.         }
  2345.  
  2346.         return $supported_methods;
  2347.     }
  2348.  
  2349.  
  2350.     /* mt.supportedTextFilters ...returns an empty array because we don't
  2351.          support per-post text filters yet */
  2352.     function mt_supportedTextFilters($args) {
  2353.         do_action('xmlrpc_call', 'mt.supportedTextFilters');
  2354.         return apply_filters('xmlrpc_text_filters', array());
  2355.     }
  2356.  
  2357.  
  2358.     /* mt.getTrackbackPings ...returns trackbacks sent to a given post */
  2359.     function mt_getTrackbackPings($args) {
  2360.  
  2361.         global $wpdb;
  2362.  
  2363.         $post_ID = intval($args);
  2364.  
  2365.         do_action('xmlrpc_call', 'mt.getTrackbackPings');
  2366.  
  2367.         $actual_post = wp_get_single_post($post_ID, ARRAY_A);
  2368.  
  2369.         if (!$actual_post) {
  2370.             return new IXR_Error(404, __('Sorry, no such post.'));
  2371.         }
  2372.  
  2373.         $comments = $wpdb->get_results( $wpdb->prepare("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = %d", $post_ID) );
  2374.  
  2375.         if (!$comments) {
  2376.             return array();
  2377.         }
  2378.  
  2379.         $trackback_pings = array();
  2380.         foreach($comments as $comment) {
  2381.             if ( 'trackback' == $comment->comment_type ) {
  2382.                 $content = $comment->comment_content;
  2383.                 $title = substr($content, 8, (strpos($content, '</strong>') - 8));
  2384.                 $trackback_pings[] = array(
  2385.                     'pingTitle' => $title,
  2386.                     'pingURL'   => $comment->comment_author_url,
  2387.                     'pingIP'    => $comment->comment_author_IP
  2388.                 );
  2389.         }
  2390.         }
  2391.  
  2392.         return $trackback_pings;
  2393.     }
  2394.  
  2395.  
  2396.     /* mt.publishPost ...sets a post's publish status to 'publish' */
  2397.     function mt_publishPost($args) {
  2398.  
  2399.         $this->escape($args);
  2400.  
  2401.         $post_ID     = (int) $args[0];
  2402.         $user_login  = $args[1];
  2403.         $user_pass   = $args[2];
  2404.  
  2405.         if (!$this->login_pass_ok($user_login, $user_pass)) {
  2406.             return $this->error;
  2407.         }
  2408.  
  2409.         do_action('xmlrpc_call', 'mt.publishPost');
  2410.  
  2411.         set_current_user(0, $user_login);
  2412.         if ( !current_user_can('edit_post', $post_ID) )
  2413.             return new IXR_Error(401, __('Sorry, you can not edit this post.'));
  2414.  
  2415.         $postdata = wp_get_single_post($post_ID,ARRAY_A);
  2416.  
  2417.         $postdata['post_status'] = 'publish';
  2418.  
  2419.         // retain old cats
  2420.         $cats = wp_get_post_categories($post_ID);
  2421.         $postdata['post_category'] = $cats;
  2422.         $this->escape($postdata);
  2423.  
  2424.         $result = wp_update_post($postdata);
  2425.  
  2426.         return $result;
  2427.     }
  2428.  
  2429.  
  2430.  
  2431.     /* PingBack functions
  2432.      * specs on www.hixie.ch/specs/pingback/pingback
  2433.      */
  2434.  
  2435.     /* pingback.ping gets a pingback and registers it */
  2436.     function pingback_ping($args) {
  2437.         global $wpdb;
  2438.  
  2439.         do_action('xmlrpc_call', 'pingback.ping');
  2440.  
  2441.         $this->escape($args);
  2442.  
  2443.         $pagelinkedfrom = $args[0];
  2444.         $pagelinkedto   = $args[1];
  2445.  
  2446.         $title = '';
  2447.  
  2448.         $pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom);
  2449.         $pagelinkedto = str_replace('&', '&', $pagelinkedto);
  2450.         $pagelinkedto = str_replace('&', '&', $pagelinkedto);
  2451.  
  2452.         // Check if the page linked to is in our site
  2453.         $pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home')));
  2454.         if( !$pos1 )
  2455.             return new IXR_Error(0, __('Is there no link to us?'));
  2456.  
  2457.         // let's find which post is linked to
  2458.         // FIXME: does url_to_postid() cover all these cases already?
  2459.         //        if so, then let's use it and drop the old code.
  2460.         $urltest = parse_url($pagelinkedto);
  2461.         if ($post_ID = url_to_postid($pagelinkedto)) {
  2462.             $way = 'url_to_postid()';
  2463.         } elseif (preg_match('#p/[0-9]{1,}#', $urltest['path'], $match)) {
  2464.             // the path defines the post_ID (archives/p/XXXX)
  2465.             $blah = explode('/', $match[0]);
  2466.             $post_ID = (int) $blah[1];
  2467.             $way = 'from the path';
  2468.         } elseif (preg_match('#p=[0-9]{1,}#', $urltest['query'], $match)) {
  2469.             // the querystring defines the post_ID (?p=XXXX)
  2470.             $blah = explode('=', $match[0]);
  2471.             $post_ID = (int) $blah[1];
  2472.             $way = 'from the querystring';
  2473.         } elseif (isset($urltest['fragment'])) {
  2474.             // an #anchor is there, it's either...
  2475.             if (intval($urltest['fragment'])) {
  2476.                 // ...an integer #XXXX (simpliest case)
  2477.                 $post_ID = (int) $urltest['fragment'];
  2478.                 $way = 'from the fragment (numeric)';
  2479.             } elseif (preg_match('/post-[0-9]+/',$urltest['fragment'])) {
  2480.                 // ...a post id in the form 'post-###'
  2481.                 $post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']);
  2482.                 $way = 'from the fragment (post-###)';
  2483.             } elseif (is_string($urltest['fragment'])) {
  2484.                 // ...or a string #title, a little more complicated
  2485.                 $title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']);
  2486.                 $sql = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title RLIKE %s", $title);
  2487.                 if (! ($post_ID = $wpdb->get_var($sql)) ) {
  2488.                     // returning unknown error '0' is better than die()ing
  2489.                       return new IXR_Error(0, '');
  2490.                 }
  2491.                 $way = 'from the fragment (title)';
  2492.             }
  2493.         } else {
  2494.             // TODO: Attempt to extract a post ID from the given URL
  2495.               return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.'));
  2496.         }
  2497.         $post_ID = (int) $post_ID;
  2498.  
  2499.  
  2500.         logIO("O","(PB) URL='$pagelinkedto' ID='$post_ID' Found='$way'");
  2501.  
  2502.         $post = get_post($post_ID);
  2503.  
  2504.         if ( !$post ) // Post_ID not found
  2505.               return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.'));
  2506.  
  2507.         if ( $post_ID == url_to_postid($pagelinkedfrom) )
  2508.             return new IXR_Error(0, __('The source URL and the target URL cannot both point to the same resource.'));
  2509.  
  2510.         // Check if pings are on
  2511.         if ( 'closed' == $post->ping_status )
  2512.               return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.'));
  2513.  
  2514.         // Let's check that the remote site didn't already pingback this entry
  2515.         $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $post_ID, $pagelinkedfrom) );
  2516.  
  2517.         if ( $wpdb->num_rows ) // We already have a Pingback from this URL
  2518.               return new IXR_Error(48, __('The pingback has already been registered.'));
  2519.  
  2520.         // very stupid, but gives time to the 'from' server to publish !
  2521.         sleep(1);
  2522.  
  2523.         // Let's check the remote site
  2524.         $linea = wp_remote_fopen( $pagelinkedfrom );
  2525.         if ( !$linea )
  2526.               return new IXR_Error(16, __('The source URL does not exist.'));
  2527.  
  2528.         $linea = apply_filters('pre_remote_source', $linea, $pagelinkedto);
  2529.  
  2530.         // Work around bug in strip_tags():
  2531.         $linea = str_replace('<!DOC', '<DOC', $linea);
  2532.         $linea = preg_replace( '/[\s\r\n\t]+/', ' ', $linea ); // normalize spaces
  2533.         $linea = preg_replace( "/ <(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $linea );
  2534.  
  2535.         preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle);
  2536.         $title = $matchtitle[1];
  2537.         if ( empty( $title ) )
  2538.             return new IXR_Error(32, __('We cannot find a title on that page.'));
  2539.  
  2540.         $linea = strip_tags( $linea, '<a>' ); // just keep the tag we need
  2541.  
  2542.         $p = explode( "\n\n", $linea );
  2543.  
  2544.         $preg_target = preg_quote($pagelinkedto);
  2545.  
  2546.         foreach ( $p as $para ) {
  2547.             if ( strpos($para, $pagelinkedto) !== false ) { // it exists, but is it a link?
  2548.                 preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context);
  2549.  
  2550.                 // If the URL isn't in a link context, keep looking
  2551.                 if ( empty($context) )
  2552.                     continue;
  2553.  
  2554.                 // We're going to use this fake tag to mark the context in a bit
  2555.                 // the marker is needed in case the link text appears more than once in the paragraph
  2556.                 $excerpt = preg_replace('|\</?wpcontext\>|', '', $para);
  2557.  
  2558.                 // prevent really long link text
  2559.                 if ( strlen($context[1]) > 100 )
  2560.                     $context[1] = substr($context[1], 0, 100) . '...';
  2561.  
  2562.                 $marker = '<wpcontext>'.$context[1].'</wpcontext>';    // set up our marker
  2563.                 $excerpt= str_replace($context[0], $marker, $excerpt); // swap out the link for our marker
  2564.                 $excerpt = strip_tags($excerpt, '<wpcontext>');        // strip all tags but our context marker
  2565.                 $excerpt = trim($excerpt);
  2566.                 $preg_marker = preg_quote($marker);
  2567.                 $excerpt = preg_replace("|.*?\s(.{0,100}$preg_marker.{0,100})\s.*|s", '$1', $excerpt);
  2568.                 $excerpt = strip_tags($excerpt); // YES, again, to remove the marker wrapper
  2569.                 break;
  2570.             }
  2571.         }
  2572.  
  2573.         if ( empty($context) ) // Link to target not found
  2574.             return new IXR_Error(17, __('The source URL does not contain a link to the target URL, and so cannot be used as a source.'));
  2575.  
  2576.         $pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom);
  2577.  
  2578.         $context = '[...] ' . wp_specialchars( $excerpt ) . ' [...]';
  2579.         $pagelinkedfrom = $wpdb->escape( $pagelinkedfrom );
  2580.  
  2581.         $comment_post_ID = (int) $post_ID;
  2582.         $comment_author = $title;
  2583.         $this->escape($comment_author);
  2584.         $comment_author_url = $pagelinkedfrom;
  2585.         $comment_content = $context;
  2586.         $this->escape($comment_content);
  2587.         $comment_type = 'pingback';
  2588.  
  2589.         $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_content', 'comment_type');
  2590.  
  2591.         $comment_ID = wp_new_comment($commentdata);
  2592.         do_action('pingback_post', $comment_ID);
  2593.  
  2594.         return sprintf(__('Pingback from %1$s to %2$s registered. Keep the web talking! :-)'), $pagelinkedfrom, $pagelinkedto);
  2595.     }
  2596.  
  2597.  
  2598.     /* pingback.extensions.getPingbacks returns an array of URLs
  2599.     that pingbacked the given URL
  2600.     specs on http://www.aquarionics.com/misc/archives/blogite/0198.html */
  2601.     function pingback_extensions_getPingbacks($args) {
  2602.  
  2603.         global $wpdb;
  2604.  
  2605.         do_action('xmlrpc_call', 'pingback.extensions.getPingsbacks');
  2606.  
  2607.         $this->escape($args);
  2608.  
  2609.         $url = $args;
  2610.  
  2611.         $post_ID = url_to_postid($url);
  2612.         if (!$post_ID) {
  2613.             // We aren't sure that the resource is available and/or pingback enabled
  2614.               return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.'));
  2615.         }
  2616.  
  2617.         $actual_post = wp_get_single_post($post_ID, ARRAY_A);
  2618.  
  2619.         if (!$actual_post) {
  2620.             // No such post = resource not found
  2621.               return new IXR_Error(32, __('The specified target URL does not exist.'));
  2622.         }
  2623.  
  2624.         $comments = $wpdb->get_results( $wpdb->prepare("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = %d", $post_ID) );
  2625.  
  2626.         if (!$comments) {
  2627.             return array();
  2628.         }
  2629.  
  2630.         $pingbacks = array();
  2631.         foreach($comments as $comment) {
  2632.             if ( 'pingback' == $comment->comment_type )
  2633.                 $pingbacks[] = $comment->comment_author_url;
  2634.         }
  2635.  
  2636.         return $pingbacks;
  2637.     }
  2638. }
  2639.  
  2640.  
  2641. $wp_xmlrpc_server = new wp_xmlrpc_server();
  2642.  
  2643. ?>
  2644.