Make WordPress Core

Changeset 15648 for trunk/xmlrpc.php


Ignore:
Timestamp:
09/23/2010 09:38:28 PM (14 years ago)
Author:
westi
Message:

Complete the move to a seperate class file for #14820 props filosofo.
Add support for replacing the class used. Fixes #14814 props filosofo.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/xmlrpc.php

    r15567 r15648  
    5353include_once(ABSPATH . 'wp-admin/includes/admin.php');
    5454include_once(ABSPATH . WPINC . '/class-IXR.php');
     55include_once(ABSPATH . WPINC . '/class.wp-xmlrpc-server.php');
    5556
    5657// Turn off all warnings and errors.
     
    9899    logIO("I", $HTTP_RAW_POST_DATA);
    99100
    100 /**
    101  * WordPress XMLRPC server implementation.
    102  *
    103  * Implements compatability for Blogger API, MetaWeblog API, MovableType, and
    104  * pingback. Additional WordPress API for managing comments, pages, posts,
    105  * options, etc.
    106  *
    107  * Since WordPress 2.6.0, WordPress XMLRPC server can be disabled in the
    108  * administration panels.
    109  *
    110  * @package WordPress
    111  * @subpackage Publishing
    112  * @since 1.5.0
    113  */
    114 class wp_xmlrpc_server extends IXR_Server {
     101// Allow for a plugin to insert a different class to handle requests.
     102$wp_xmlrpc_server_class = apply_filters('wp_xmlrpc_server_class', 'wp_xmlrpc_server');
     103$wp_xmlrpc_server = new $wp_xmlrpc_server_class;
    115104
    116     /**
    117      * Register all of the XMLRPC methods that XMLRPC server understands.
    118      *
    119      * PHP4 constructor and sets up server and method property. Passes XMLRPC
    120      * methods through the 'xmlrpc_methods' filter to allow plugins to extend
    121      * or replace XMLRPC methods.
    122      *
    123      * @since 1.5.0
    124      *
    125      * @return wp_xmlrpc_server
    126      */
    127     function wp_xmlrpc_server() {
    128         $this->methods = array(
    129             // WordPress API
    130             'wp.getUsersBlogs'      => 'this:wp_getUsersBlogs',
    131             'wp.getPage'            => 'this:wp_getPage',
    132             'wp.getPages'           => 'this:wp_getPages',
    133             'wp.newPage'            => 'this:wp_newPage',
    134             'wp.deletePage'         => 'this:wp_deletePage',
    135             'wp.editPage'           => 'this:wp_editPage',
    136             'wp.getPageList'        => 'this:wp_getPageList',
    137             'wp.getAuthors'         => 'this:wp_getAuthors',
    138             'wp.getCategories'      => 'this:mw_getCategories',     // Alias
    139             'wp.getTags'            => 'this:wp_getTags',
    140             'wp.newCategory'        => 'this:wp_newCategory',
    141             'wp.deleteCategory'     => 'this:wp_deleteCategory',
    142             'wp.suggestCategories'  => 'this:wp_suggestCategories',
    143             'wp.uploadFile'         => 'this:mw_newMediaObject',    // Alias
    144             'wp.getCommentCount'    => 'this:wp_getCommentCount',
    145             'wp.getPostStatusList'  => 'this:wp_getPostStatusList',
    146             'wp.getPageStatusList'  => 'this:wp_getPageStatusList',
    147             'wp.getPageTemplates'   => 'this:wp_getPageTemplates',
    148             'wp.getOptions'         => 'this:wp_getOptions',
    149             'wp.setOptions'         => 'this:wp_setOptions',
    150             'wp.getComment'         => 'this:wp_getComment',
    151             'wp.getComments'        => 'this:wp_getComments',
    152             'wp.deleteComment'      => 'this:wp_deleteComment',
    153             'wp.editComment'        => 'this:wp_editComment',
    154             'wp.newComment'         => 'this:wp_newComment',
    155             'wp.getCommentStatusList' => 'this:wp_getCommentStatusList',
    156 
    157             // Blogger API
    158             'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
    159             'blogger.getUserInfo' => 'this:blogger_getUserInfo',
    160             'blogger.getPost' => 'this:blogger_getPost',
    161             'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
    162             'blogger.getTemplate' => 'this:blogger_getTemplate',
    163             'blogger.setTemplate' => 'this:blogger_setTemplate',
    164             'blogger.newPost' => 'this:blogger_newPost',
    165             'blogger.editPost' => 'this:blogger_editPost',
    166             'blogger.deletePost' => 'this:blogger_deletePost',
    167 
    168             // MetaWeblog API (with MT extensions to structs)
    169             'metaWeblog.newPost' => 'this:mw_newPost',
    170             'metaWeblog.editPost' => 'this:mw_editPost',
    171             'metaWeblog.getPost' => 'this:mw_getPost',
    172             'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
    173             'metaWeblog.getCategories' => 'this:mw_getCategories',
    174             'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
    175 
    176             // MetaWeblog API aliases for Blogger API
    177             // see http://www.xmlrpc.com/stories/storyReader$2460
    178             'metaWeblog.deletePost' => 'this:blogger_deletePost',
    179             'metaWeblog.getTemplate' => 'this:blogger_getTemplate',
    180             'metaWeblog.setTemplate' => 'this:blogger_setTemplate',
    181             'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
    182 
    183             // MovableType API
    184             'mt.getCategoryList' => 'this:mt_getCategoryList',
    185             'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
    186             'mt.getPostCategories' => 'this:mt_getPostCategories',
    187             'mt.setPostCategories' => 'this:mt_setPostCategories',
    188             'mt.supportedMethods' => 'this:mt_supportedMethods',
    189             'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
    190             'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
    191             'mt.publishPost' => 'this:mt_publishPost',
    192 
    193             // PingBack
    194             'pingback.ping' => 'this:pingback_ping',
    195             'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',
    196 
    197             'demo.sayHello' => 'this:sayHello',
    198             'demo.addTwoNumbers' => 'this:addTwoNumbers'
    199         );
    200 
    201         $this->initialise_blog_option_info( );
    202         $this->methods = apply_filters('xmlrpc_methods', $this->methods);
    203     }
    204 
    205     function serve_request() {
    206         $this->IXR_Server($this->methods);
    207     }
    208 
    209     /**
    210      * Test XMLRPC API by saying, "Hello!" to client.
    211      *
    212      * @since 1.5.0
    213      *
    214      * @param array $args Method Parameters.
    215      * @return string
    216      */
    217     function sayHello($args) {
    218         return 'Hello!';
    219     }
    220 
    221     /**
    222      * Test XMLRPC API by adding two numbers for client.
    223      *
    224      * @since 1.5.0
    225      *
    226      * @param array $args Method Parameters.
    227      * @return int
    228      */
    229     function addTwoNumbers($args) {
    230         $number1 = $args[0];
    231         $number2 = $args[1];
    232         return $number1 + $number2;
    233     }
    234 
    235     /**
    236      * Check user's credentials.
    237      *
    238      * @since 1.5.0
    239      *
    240      * @param string $user_login User's username.
    241      * @param string $user_pass User's password.
    242      * @return bool Whether authentication passed.
    243      * @deprecated use wp_xmlrpc_server::login
    244      * @see wp_xmlrpc_server::login
    245      */
    246     function login_pass_ok($user_login, $user_pass) {
    247         if ( !get_option( 'enable_xmlrpc' ) ) {
    248             $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.  An admin user can enable them at %s'),  admin_url('options-writing.php') ) );
    249             return false;
    250         }
    251 
    252         if (!user_pass_ok($user_login, $user_pass)) {
    253             $this->error = new IXR_Error(403, __('Bad login/pass combination.'));
    254             return false;
    255         }
    256         return true;
    257     }
    258 
    259     /**
    260      * Log user in.
    261      *
    262      * @since 2.8
    263      *
    264      * @param string $username User's username.
    265      * @param string $password User's password.
    266      * @return mixed WP_User object if authentication passed, false otherwise
    267      */
    268     function login($username, $password) {
    269         if ( !get_option( 'enable_xmlrpc' ) ) {
    270             $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.  An admin user can enable them at %s'),  admin_url('options-writing.php') ) );
    271             return false;
    272         }
    273 
    274         $user = wp_authenticate($username, $password);
    275 
    276         if (is_wp_error($user)) {
    277             $this->error = new IXR_Error(403, __('Bad login/pass combination.'));
    278             return false;
    279         }
    280 
    281         wp_set_current_user( $user->ID );
    282         return $user;
    283     }
    284 
    285     /**
    286      * Sanitize string or array of strings for database.
    287      *
    288      * @since 1.5.2
    289      *
    290      * @param string|array $array Sanitize single string or array of strings.
    291      * @return string|array Type matches $array and sanitized for the database.
    292      */
    293     function escape(&$array) {
    294         global $wpdb;
    295 
    296         if (!is_array($array)) {
    297             return($wpdb->escape($array));
    298         } else {
    299             foreach ( (array) $array as $k => $v ) {
    300                 if ( is_array($v) ) {
    301                     $this->escape($array[$k]);
    302                 } else if ( is_object($v) ) {
    303                     //skip
    304                 } else {
    305                     $array[$k] = $wpdb->escape($v);
    306                 }
    307             }
    308         }
    309     }
    310 
    311     /**
    312      * Retrieve custom fields for post.
    313      *
    314      * @since 2.5.0
    315      *
    316      * @param int $post_id Post ID.
    317      * @return array Custom fields, if exist.
    318      */
    319     function get_custom_fields($post_id) {
    320         $post_id = (int) $post_id;
    321 
    322         $custom_fields = array();
    323 
    324         foreach ( (array) has_meta($post_id) as $meta ) {
    325             // Don't expose protected fields.
    326             if ( strpos($meta['meta_key'], '_wp_') === 0 ) {
    327                 continue;
    328             }
    329 
    330             $custom_fields[] = array(
    331                 "id"    => $meta['meta_id'],
    332                 "key"   => $meta['meta_key'],
    333                 "value" => $meta['meta_value']
    334             );
    335         }
    336 
    337         return $custom_fields;
    338     }
    339 
    340     /**
    341      * Set custom fields for post.
    342      *
    343      * @since 2.5.0
    344      *
    345      * @param int $post_id Post ID.
    346      * @param array $fields Custom fields.
    347      */
    348     function set_custom_fields($post_id, $fields) {
    349         $post_id = (int) $post_id;
    350 
    351         foreach ( (array) $fields as $meta ) {
    352             if ( isset($meta['id']) ) {
    353                 $meta['id'] = (int) $meta['id'];
    354 
    355                 if ( isset($meta['key']) ) {
    356                     update_meta($meta['id'], $meta['key'], $meta['value']);
    357                 }
    358                 else {
    359                     delete_meta($meta['id']);
    360                 }
    361             }
    362             else {
    363                 $_POST['metakeyinput'] = $meta['key'];
    364                 $_POST['metavalue'] = $meta['value'];
    365                 add_meta($post_id);
    366             }
    367         }
    368     }
    369 
    370     /**
    371      * Set up blog options property.
    372      *
    373      * Passes property through 'xmlrpc_blog_options' filter.
    374      *
    375      * @since 2.6.0
    376      */
    377     function initialise_blog_option_info( ) {
    378         global $wp_version;
    379 
    380         $this->blog_options = array(
    381             // Read only options
    382             'software_name'     => array(
    383                 'desc'          => __( 'Software Name' ),
    384                 'readonly'      => true,
    385                 'value'         => 'WordPress'
    386             ),
    387             'software_version'  => array(
    388                 'desc'          => __( 'Software Version' ),
    389                 'readonly'      => true,
    390                 'value'         => $wp_version
    391             ),
    392             'blog_url'          => array(
    393                 'desc'          => __( 'Site URL' ),
    394                 'readonly'      => true,
    395                 'option'        => 'siteurl'
    396             ),
    397 
    398             // Updatable options
    399             'time_zone'         => array(
    400                 'desc'          => __( 'Time Zone' ),
    401                 'readonly'      => false,
    402                 'option'        => 'gmt_offset'
    403             ),
    404             'blog_title'        => array(
    405                 'desc'          => __( 'Site Title' ),
    406                 'readonly'      => false,
    407                 'option'            => 'blogname'
    408             ),
    409             'blog_tagline'      => array(
    410                 'desc'          => __( 'Site Tagline' ),
    411                 'readonly'      => false,
    412                 'option'        => 'blogdescription'
    413             ),
    414             'date_format'       => array(
    415                 'desc'          => __( 'Date Format' ),
    416                 'readonly'      => false,
    417                 'option'        => 'date_format'
    418             ),
    419             'time_format'       => array(
    420                 'desc'          => __( 'Time Format' ),
    421                 'readonly'      => false,
    422                 'option'        => 'time_format'
    423             ),
    424             'users_can_register'    => array(
    425                 'desc'          => __( 'Allow new users to sign up' ),
    426                 'readonly'      => false,
    427                 'option'        => 'users_can_register'
    428             )
    429         );
    430 
    431         $this->blog_options = apply_filters( 'xmlrpc_blog_options', $this->blog_options );
    432     }
    433 
    434     /**
    435      * Retrieve the blogs of the user.
    436      *
    437      * @since 2.6.0
    438      *
    439      * @param array $args Method parameters.
    440      * @return array
    441      */
    442     function wp_getUsersBlogs( $args ) {
    443         global $current_site;
    444         // If this isn't on WPMU then just use blogger_getUsersBlogs
    445         if ( !is_multisite() ) {
    446             array_unshift( $args, 1 );
    447             return $this->blogger_getUsersBlogs( $args );
    448         }
    449 
    450         $this->escape( $args );
    451 
    452         $username = $args[0];
    453         $password = $args[1];
    454 
    455         if ( !$user = $this->login($username, $password) )
    456             return $this->error;
    457 
    458 
    459         do_action( 'xmlrpc_call', 'wp.getUsersBlogs' );
    460 
    461         $blogs = (array) get_blogs_of_user( $user->ID );
    462         $struct = array( );
    463 
    464         foreach ( $blogs as $blog ) {
    465             // Don't include blogs that aren't hosted at this site
    466             if ( $blog->site_id != $current_site->id )
    467                 continue;
    468 
    469             $blog_id = $blog->userblog_id;
    470             switch_to_blog($blog_id);
    471             $is_admin = current_user_can('manage_options');
    472 
    473             $struct[] = array(
    474                 'isAdmin'       => $is_admin,
    475                 'url'           => get_option( 'home' ) . '/',
    476                 'blogid'        => $blog_id,
    477                 'blogName'      => get_option( 'blogname' ),
    478                 'xmlrpc'        => site_url( 'xmlrpc.php' )
    479             );
    480 
    481             restore_current_blog( );
    482         }
    483 
    484         return $struct;
    485     }
    486 
    487     /**
    488      * Retrieve page.
    489      *
    490      * @since 2.2.0
    491      *
    492      * @param array $args Method parameters.
    493      * @return array
    494      */
    495     function wp_getPage($args) {
    496         $this->escape($args);
    497 
    498         $blog_id    = (int) $args[0];
    499         $page_id    = (int) $args[1];
    500         $username   = $args[2];
    501         $password   = $args[3];
    502 
    503         if ( !$user = $this->login($username, $password) ) {
    504             return $this->error;
    505         }
    506 
    507         if ( !current_user_can( 'edit_page', $page_id ) )
    508             return new IXR_Error( 401, __( 'Sorry, you cannot edit this page.' ) );
    509 
    510         do_action('xmlrpc_call', 'wp.getPage');
    511 
    512         // Lookup page info.
    513         $page = get_page($page_id);
    514 
    515         // If we found the page then format the data.
    516         if ( $page->ID && ($page->post_type == "page") ) {
    517             // Get all of the page content and link.
    518             $full_page = get_extended($page->post_content);
    519             $link = post_permalink($page->ID);
    520 
    521             // Get info the page parent if there is one.
    522             $parent_title = "";
    523             if ( !empty($page->post_parent) ) {
    524                 $parent = get_page($page->post_parent);
    525                 $parent_title = $parent->post_title;
    526             }
    527 
    528             // Determine comment and ping settings.
    529             $allow_comments = comments_open($page->ID) ? 1 : 0;
    530             $allow_pings = pings_open($page->ID) ? 1 : 0;
    531 
    532             // Format page date.
    533             $page_date = mysql2date("Ymd\TH:i:s", $page->post_date, false);
    534             $page_date_gmt = mysql2date("Ymd\TH:i:s", $page->post_date_gmt, false);
    535 
    536             // For drafts use the GMT version of the date
    537             if ( $page->post_status == 'draft' )
    538                 $page_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $page->post_date ), 'Ymd\TH:i:s' );
    539 
    540             // Pull the categories info together.
    541             $categories = array();
    542             foreach ( wp_get_post_categories($page->ID) as $cat_id ) {
    543                 $categories[] = get_cat_name($cat_id);
    544             }
    545 
    546             // Get the author info.
    547             $author = get_userdata($page->post_author);
    548 
    549             $page_template = get_post_meta( $page->ID, '_wp_page_template', true );
    550             if ( empty( $page_template ) )
    551                 $page_template = 'default';
    552 
    553             $page_struct = array(
    554                 "dateCreated"           => new IXR_Date($page_date),
    555                 "userid"                => $page->post_author,
    556                 "page_id"               => $page->ID,
    557                 "page_status"           => $page->post_status,
    558                 "description"           => $full_page["main"],
    559                 "title"                 => $page->post_title,
    560                 "link"                  => $link,
    561                 "permaLink"             => $link,
    562                 "categories"            => $categories,
    563                 "excerpt"               => $page->post_excerpt,
    564                 "text_more"             => $full_page["extended"],
    565                 "mt_allow_comments"     => $allow_comments,
    566                 "mt_allow_pings"        => $allow_pings,
    567                 "wp_slug"               => $page->post_name,
    568                 "wp_password"           => $page->post_password,
    569                 "wp_author"             => $author->display_name,
    570                 "wp_page_parent_id"     => $page->post_parent,
    571                 "wp_page_parent_title"  => $parent_title,
    572                 "wp_page_order"         => $page->menu_order,
    573                 "wp_author_id"          => $author->ID,
    574                 "wp_author_display_name"    => $author->display_name,
    575                 "date_created_gmt"      => new IXR_Date($page_date_gmt),
    576                 "custom_fields"         => $this->get_custom_fields($page_id),
    577                 "wp_page_template"      => $page_template
    578             );
    579 
    580             return($page_struct);
    581         }
    582         // If the page doesn't exist indicate that.
    583         else {
    584             return(new IXR_Error(404, __("Sorry, no such page.")));
    585         }
    586     }
    587 
    588     /**
    589      * Retrieve Pages.
    590      *
    591      * @since 2.2.0
    592      *
    593      * @param array $args Method parameters.
    594      * @return array
    595      */
    596     function wp_getPages($args) {
    597         $this->escape($args);
    598 
    599         $blog_id    = (int) $args[0];
    600         $username   = $args[1];
    601         $password   = $args[2];
    602         $num_pages  = isset($args[3]) ? (int) $args[3] : 10;
    603 
    604         if ( !$user = $this->login($username, $password) )
    605             return $this->error;
    606 
    607         if ( !current_user_can( 'edit_pages' ) )
    608             return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) );
    609 
    610         do_action('xmlrpc_call', 'wp.getPages');
    611 
    612         $pages = get_posts( array('post_type' => 'page', 'post_status' => 'any', 'numberposts' => $num_pages) );
    613         $num_pages = count($pages);
    614 
    615         // If we have pages, put together their info.
    616         if ( $num_pages >= 1 ) {
    617             $pages_struct = array();
    618 
    619             for ( $i = 0; $i < $num_pages; $i++ ) {
    620                 $page = wp_xmlrpc_server::wp_getPage(array(
    621                     $blog_id, $pages[$i]->ID, $username, $password
    622                 ));
    623                 $pages_struct[] = $page;
    624             }
    625 
    626             return($pages_struct);
    627         }
    628         // If no pages were found return an error.
    629         else {
    630             return(array());
    631         }
    632     }
    633 
    634     /**
    635      * Create new page.
    636      *
    637      * @since 2.2.0
    638      *
    639      * @param array $args Method parameters.
    640      * @return unknown
    641      */
    642     function wp_newPage($args) {
    643         // Items not escaped here will be escaped in newPost.
    644         $username   = $this->escape($args[1]);
    645         $password   = $this->escape($args[2]);
    646         $page       = $args[3];
    647         $publish    = $args[4];
    648 
    649         if ( !$user = $this->login($username, $password) )
    650             return $this->error;
    651 
    652         do_action('xmlrpc_call', 'wp.newPage');
    653 
    654         // Make sure the user is allowed to add new pages.
    655         if ( !current_user_can("publish_pages") )
    656             return(new IXR_Error(401, __("Sorry, you cannot add new pages.")));
    657 
    658         // Mark this as content for a page.
    659         $args[3]["post_type"] = "page";
    660 
    661         // Let mw_newPost do all of the heavy lifting.
    662         return($this->mw_newPost($args));
    663     }
    664 
    665     /**
    666      * Delete page.
    667      *
    668      * @since 2.2.0
    669      *
    670      * @param array $args Method parameters.
    671      * @return bool True, if success.
    672      */
    673     function wp_deletePage($args) {
    674         $this->escape($args);
    675 
    676         $blog_id    = (int) $args[0];
    677         $username   = $args[1];
    678         $password   = $args[2];
    679         $page_id    = (int) $args[3];
    680 
    681         if ( !$user = $this->login($username, $password) )
    682             return $this->error;
    683 
    684         do_action('xmlrpc_call', 'wp.deletePage');
    685 
    686         // Get the current page based on the page_id and
    687         // make sure it is a page and not a post.
    688         $actual_page = wp_get_single_post($page_id, ARRAY_A);
    689         if ( !$actual_page || ($actual_page["post_type"] != "page") )
    690             return(new IXR_Error(404, __("Sorry, no such page.")));
    691 
    692         // Make sure the user can delete pages.
    693         if ( !current_user_can("delete_page", $page_id) )
    694             return(new IXR_Error(401, __("Sorry, you do not have the right to delete this page.")));
    695 
    696         // Attempt to delete the page.
    697         $result = wp_delete_post($page_id);
    698         if ( !$result )
    699             return(new IXR_Error(500, __("Failed to delete the page.")));
    700 
    701         return(true);
    702     }
    703 
    704     /**
    705      * Edit page.
    706      *
    707      * @since 2.2.0
    708      *
    709      * @param array $args Method parameters.
    710      * @return unknown
    711      */
    712     function wp_editPage($args) {
    713         // Items not escaped here will be escaped in editPost.
    714         $blog_id    = (int) $args[0];
    715         $page_id    = (int) $this->escape($args[1]);
    716         $username   = $this->escape($args[2]);
    717         $password   = $this->escape($args[3]);
    718         $content    = $args[4];
    719         $publish    = $args[5];
    720 
    721         if ( !$user = $this->login($username, $password) )
    722             return $this->error;
    723 
    724         do_action('xmlrpc_call', 'wp.editPage');
    725 
    726         // Get the page data and make sure it is a page.
    727         $actual_page = wp_get_single_post($page_id, ARRAY_A);
    728         if ( !$actual_page || ($actual_page["post_type"] != "page") )
    729             return(new IXR_Error(404, __("Sorry, no such page.")));
    730 
    731         // Make sure the user is allowed to edit pages.
    732         if ( !current_user_can("edit_page", $page_id) )
    733             return(new IXR_Error(401, __("Sorry, you do not have the right to edit this page.")));
    734 
    735         // Mark this as content for a page.
    736         $content["post_type"] = "page";
    737 
    738         // Arrange args in the way mw_editPost understands.
    739         $args = array(
    740             $page_id,
    741             $username,
    742             $password,
    743             $content,
    744             $publish
    745         );
    746 
    747         // Let mw_editPost do all of the heavy lifting.
    748         return($this->mw_editPost($args));
    749     }
    750 
    751     /**
    752      * Retrieve page list.
    753      *
    754      * @since 2.2.0
    755      *
    756      * @param array $args Method parameters.
    757      * @return unknown
    758      */
    759     function wp_getPageList($args) {
    760         global $wpdb;
    761 
    762         $this->escape($args);
    763 
    764         $blog_id                = (int) $args[0];
    765         $username               = $args[1];
    766         $password               = $args[2];
    767 
    768         if ( !$user = $this->login($username, $password) )
    769             return $this->error;
    770 
    771         if ( !current_user_can( 'edit_pages' ) )
    772             return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) );
    773 
    774         do_action('xmlrpc_call', 'wp.getPageList');
    775 
    776         // Get list of pages ids and titles
    777         $page_list = $wpdb->get_results("
    778             SELECT ID page_id,
    779                 post_title page_title,
    780                 post_parent page_parent_id,
    781                 post_date_gmt,
    782                 post_date,
    783                 post_status
    784             FROM {$wpdb->posts}
    785             WHERE post_type = 'page'
    786             ORDER BY ID
    787         ");
    788 
    789         // The date needs to be formated properly.
    790         $num_pages = count($page_list);
    791         for ( $i = 0; $i < $num_pages; $i++ ) {
    792             $post_date = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date, false);
    793             $post_date_gmt = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date_gmt, false);
    794 
    795             $page_list[$i]->dateCreated = new IXR_Date($post_date);
    796             $page_list[$i]->date_created_gmt = new IXR_Date($post_date_gmt);
    797 
    798             // For drafts use the GMT version of the date
    799             if ( $page_list[$i]->post_status == 'draft' ) {
    800                 $page_list[$i]->date_created_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $page_list[$i]->post_date ), 'Ymd\TH:i:s' );
    801                 $page_list[$i]->date_created_gmt = new IXR_Date( $page_list[$i]->date_created_gmt );
    802             }
    803 
    804             unset($page_list[$i]->post_date_gmt);
    805             unset($page_list[$i]->post_date);
    806             unset($page_list[$i]->post_status);
    807         }
    808 
    809         return($page_list);
    810     }
    811 
    812     /**
    813      * Retrieve authors list.
    814      *
    815      * @since 2.2.0
    816      *
    817      * @param array $args Method parameters.
    818      * @return array
    819      */
    820     function wp_getAuthors($args) {
    821 
    822         $this->escape($args);
    823 
    824         $blog_id    = (int) $args[0];
    825         $username   = $args[1];
    826         $password   = $args[2];
    827 
    828         if ( !$user = $this->login($username, $password) )
    829             return $this->error;
    830 
    831         if ( !current_user_can("edit_posts") )
    832             return(new IXR_Error(401, __("Sorry, you cannot edit posts on this site.")));
    833 
    834         do_action('xmlrpc_call', 'wp.getAuthors');
    835 
    836         $authors = array();
    837         foreach ( get_users() as $user_id => $user_object ) {
    838             $authors[] = array(
    839                 "user_id"       => $user_id,
    840                 "user_login"    => $user_object->user_login,
    841                 "display_name"  => $user_object->display_name
    842             );
    843         }
    844 
    845         return $authors;
    846     }
    847 
    848     /**
    849      * Get list of all tags
    850      *
    851      * @since 2.7
    852      *
    853      * @param array $args Method parameters.
    854      * @return array
    855      */
    856     function wp_getTags( $args ) {
    857         $this->escape( $args );
    858 
    859         $blog_id        = (int) $args[0];
    860         $username       = $args[1];
    861         $password       = $args[2];
    862 
    863         if ( !$user = $this->login($username, $password) )
    864             return $this->error;
    865 
    866         if ( !current_user_can( 'edit_posts' ) )
    867             return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view tags.' ) );
    868 
    869         do_action( 'xmlrpc_call', 'wp.getKeywords' );
    870 
    871         $tags = array( );
    872 
    873         if ( $all_tags = get_tags() ) {
    874             foreach( (array) $all_tags as $tag ) {
    875                 $struct['tag_id']           = $tag->term_id;
    876                 $struct['name']             = $tag->name;
    877                 $struct['count']            = $tag->count;
    878                 $struct['slug']             = $tag->slug;
    879                 $struct['html_url']         = esc_html( get_tag_link( $tag->term_id ) );
    880                 $struct['rss_url']          = esc_html( get_tag_feed_link( $tag->term_id ) );
    881 
    882                 $tags[] = $struct;
    883             }
    884         }
    885 
    886         return $tags;
    887     }
    888 
    889     /**
    890      * Create new category.
    891      *
    892      * @since 2.2.0
    893      *
    894      * @param array $args Method parameters.
    895      * @return int Category ID.
    896      */
    897     function wp_newCategory($args) {
    898         $this->escape($args);
    899 
    900         $blog_id                = (int) $args[0];
    901         $username               = $args[1];
    902         $password               = $args[2];
    903         $category               = $args[3];
    904 
    905         if ( !$user = $this->login($username, $password) )
    906             return $this->error;
    907 
    908         do_action('xmlrpc_call', 'wp.newCategory');
    909 
    910         // Make sure the user is allowed to add a category.
    911         if ( !current_user_can("manage_categories") )
    912             return(new IXR_Error(401, __("Sorry, you do not have the right to add a category.")));
    913 
    914         // If no slug was provided make it empty so that
    915         // WordPress will generate one.
    916         if ( empty($category["slug"]) )
    917             $category["slug"] = "";
    918 
    919         // If no parent_id was provided make it empty
    920         // so that it will be a top level page (no parent).
    921         if ( !isset($category["parent_id"]) )
    922             $category["parent_id"] = "";
    923 
    924         // If no description was provided make it empty.
    925         if ( empty($category["description"]) )
    926             $category["description"] = "";
    927 
    928         $new_category = array(
    929             "cat_name"              => $category["name"],
    930             "category_nicename"     => $category["slug"],
    931             "category_parent"       => $category["parent_id"],
    932             "category_description"  => $category["description"]
    933         );
    934 
    935         $cat_id = wp_insert_category($new_category, true);
    936         if ( is_wp_error( $cat_id ) ) {
    937             if ( 'term_exists' == $cat_id->get_error_code() )
    938                 return (int) $cat_id->get_error_data();
    939             else
    940                 return(new IXR_Error(500, __("Sorry, the new category failed.")));
    941         } elseif ( ! $cat_id ) {
    942             return(new IXR_Error(500, __("Sorry, the new category failed.")));
    943         }
    944 
    945         return($cat_id);
    946     }
    947 
    948     /**
    949      * Remove category.
    950      *
    951      * @since 2.5.0
    952      *
    953      * @param array $args Method parameters.
    954      * @return mixed See {@link wp_delete_category()} for return info.
    955      */
    956     function wp_deleteCategory($args) {
    957         $this->escape($args);
    958 
    959         $blog_id        = (int) $args[0];
    960         $username       = $args[1];
    961         $password       = $args[2];
    962         $category_id    = (int) $args[3];
    963 
    964         if ( !$user = $this->login($username, $password) )
    965             return $this->error;
    966 
    967         do_action('xmlrpc_call', 'wp.deleteCategory');
    968 
    969         if ( !current_user_can("manage_categories") )
    970             return new IXR_Error( 401, __( "Sorry, you do not have the right to delete a category." ) );
    971 
    972         return wp_delete_category( $category_id );
    973     }
    974 
    975     /**
    976      * Retrieve category list.
    977      *
    978      * @since 2.2.0
    979      *
    980      * @param array $args Method parameters.
    981      * @return array
    982      */
    983     function wp_suggestCategories($args) {
    984         $this->escape($args);
    985 
    986         $blog_id                = (int) $args[0];
    987         $username               = $args[1];
    988         $password               = $args[2];
    989         $category               = $args[3];
    990         $max_results            = (int) $args[4];
    991 
    992         if ( !$user = $this->login($username, $password) )
    993             return $this->error;
    994 
    995         if ( !current_user_can( 'edit_posts' ) )
    996             return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts to this site in order to view categories.' ) );
    997 
    998         do_action('xmlrpc_call', 'wp.suggestCategories');
    999 
    1000         $category_suggestions = array();
    1001         $args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category);
    1002         foreach ( (array) get_categories($args) as $cat ) {
    1003             $category_suggestions[] = array(
    1004                 "category_id"   => $cat->cat_ID,
    1005                 "category_name" => $cat->cat_name
    1006             );
    1007         }
    1008 
    1009         return($category_suggestions);
    1010     }
    1011 
    1012     /**
    1013      * Retrieve comment.
    1014      *
    1015      * @since 2.7.0
    1016      *
    1017      * @param array $args Method parameters.
    1018      * @return array
    1019      */
    1020     function wp_getComment($args) {
    1021         $this->escape($args);
    1022 
    1023         $blog_id    = (int) $args[0];
    1024         $username   = $args[1];
    1025         $password   = $args[2];
    1026         $comment_id = (int) $args[3];
    1027 
    1028         if ( !$user = $this->login($username, $password) )
    1029             return $this->error;
    1030 
    1031         if ( !current_user_can( 'moderate_comments' ) )
    1032             return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
    1033 
    1034         do_action('xmlrpc_call', 'wp.getComment');
    1035 
    1036         if ( ! $comment = get_comment($comment_id) )
    1037             return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
    1038 
    1039         // Format page date.
    1040         $comment_date = mysql2date("Ymd\TH:i:s", $comment->comment_date, false);
    1041         $comment_date_gmt = mysql2date("Ymd\TH:i:s", $comment->comment_date_gmt, false);
    1042 
    1043         if ( '0' == $comment->comment_approved )
    1044             $comment_status = 'hold';
    1045         else if ( 'spam' == $comment->comment_approved )
    1046             $comment_status = 'spam';
    1047         else if ( '1' == $comment->comment_approved )
    1048             $comment_status = 'approve';
    1049         else
    1050             $comment_status = $comment->comment_approved;
    1051 
    1052         $link = get_comment_link($comment);
    1053 
    1054         $comment_struct = array(
    1055             "date_created_gmt"      => new IXR_Date($comment_date_gmt),
    1056             "user_id"               => $comment->user_id,
    1057             "comment_id"            => $comment->comment_ID,
    1058             "parent"                => $comment->comment_parent,
    1059             "status"                => $comment_status,
    1060             "content"               => $comment->comment_content,
    1061             "link"                  => $link,
    1062             "post_id"               => $comment->comment_post_ID,
    1063             "post_title"            => get_the_title($comment->comment_post_ID),
    1064             "author"                => $comment->comment_author,
    1065             "author_url"            => $comment->comment_author_url,
    1066             "author_email"          => $comment->comment_author_email,
    1067             "author_ip"             => $comment->comment_author_IP,
    1068             "type"                  => $comment->comment_type,
    1069         );
    1070 
    1071         return $comment_struct;
    1072     }
    1073 
    1074     /**
    1075      * Retrieve comments.
    1076      *
    1077      * @since 2.7.0
    1078      *
    1079      * @param array $args Method parameters.
    1080      * @return array
    1081      */
    1082     function wp_getComments($args) {
    1083         $raw_args = $args;
    1084         $this->escape($args);
    1085 
    1086         $blog_id    = (int) $args[0];
    1087         $username   = $args[1];
    1088         $password   = $args[2];
    1089         $struct     = $args[3];
    1090 
    1091         if ( !$user = $this->login($username, $password) )
    1092             return $this->error;
    1093 
    1094         if ( !current_user_can( 'moderate_comments' ) )
    1095             return new IXR_Error( 401, __( 'Sorry, you cannot edit comments.' ) );
    1096 
    1097         do_action('xmlrpc_call', 'wp.getComments');
    1098 
    1099         if ( isset($struct['status']) )
    1100             $status = $struct['status'];
    1101         else
    1102             $status = '';
    1103 
    1104         $post_id = '';
    1105         if ( isset($struct['post_id']) )
    1106             $post_id = absint($struct['post_id']);
    1107 
    1108         $offset = 0;
    1109         if ( isset($struct['offset']) )
    1110             $offset = absint($struct['offset']);
    1111 
    1112         $number = 10;
    1113         if ( isset($struct['number']) )
    1114             $number = absint($struct['number']);
    1115 
    1116         $comments = get_comments( array('status' => $status, 'post_id' => $post_id, 'offset' => $offset, 'number' => $number ) );
    1117         $num_comments = count($comments);
    1118 
    1119         if ( ! $num_comments )
    1120             return array();
    1121 
    1122         $comments_struct = array();
    1123 
    1124         for ( $i = 0; $i < $num_comments; $i++ ) {
    1125             $comment = wp_xmlrpc_server::wp_getComment(array(
    1126                 $raw_args[0], $raw_args[1], $raw_args[2], $comments[$i]->comment_ID,
    1127             ));
    1128             $comments_struct[] = $comment;
    1129         }
    1130 
    1131         return $comments_struct;
    1132     }
    1133 
    1134     /**
    1135      * Remove comment.
    1136      *
    1137      * @since 2.7.0
    1138      *
    1139      * @param array $args Method parameters.
    1140      * @return mixed {@link wp_delete_comment()}
    1141      */
    1142     function wp_deleteComment($args) {
    1143         $this->escape($args);
    1144 
    1145         $blog_id    = (int) $args[0];
    1146         $username   = $args[1];
    1147         $password   = $args[2];
    1148         $comment_ID = (int) $args[3];
    1149 
    1150         if ( !$user = $this->login($username, $password) )
    1151             return $this->error;
    1152 
    1153         if ( !current_user_can( 'moderate_comments' ) )
    1154             return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
    1155 
    1156         do_action('xmlrpc_call', 'wp.deleteComment');
    1157 
    1158         if ( ! get_comment($comment_ID) )
    1159             return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
    1160 
    1161         return wp_delete_comment($comment_ID);
    1162     }
    1163 
    1164     /**
    1165      * Edit comment.
    1166      *
    1167      * @since 2.7.0
    1168      *
    1169      * @param array $args Method parameters.
    1170      * @return bool True, on success.
    1171      */
    1172     function wp_editComment($args) {
    1173         $this->escape($args);
    1174 
    1175         $blog_id    = (int) $args[0];
    1176         $username   = $args[1];
    1177         $password   = $args[2];
    1178         $comment_ID = (int) $args[3];
    1179         $content_struct = $args[4];
    1180 
    1181         if ( !$user = $this->login($username, $password) )
    1182             return $this->error;
    1183 
    1184         if ( !current_user_can( 'moderate_comments' ) )
    1185             return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
    1186 
    1187         do_action('xmlrpc_call', 'wp.editComment');
    1188 
    1189         if ( ! get_comment($comment_ID) )
    1190             return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
    1191 
    1192         if ( isset($content_struct['status']) ) {
    1193             $statuses = get_comment_statuses();
    1194             $statuses = array_keys($statuses);
    1195 
    1196             if ( ! in_array($content_struct['status'], $statuses) )
    1197                 return new IXR_Error( 401, __( 'Invalid comment status.' ) );
    1198             $comment_approved = $content_struct['status'];
    1199         }
    1200 
    1201         // Do some timestamp voodoo
    1202         if ( !empty( $content_struct['date_created_gmt'] ) ) {
    1203             $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
    1204             $comment_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
    1205             $comment_date_gmt = iso8601_to_datetime($dateCreated, GMT);
    1206         }
    1207 
    1208         if ( isset($content_struct['content']) )
    1209             $comment_content = $content_struct['content'];
    1210 
    1211         if ( isset($content_struct['author']) )
    1212             $comment_author = $content_struct['author'];
    1213 
    1214         if ( isset($content_struct['author_url']) )
    1215             $comment_author_url = $content_struct['author_url'];
    1216 
    1217         if ( isset($content_struct['author_email']) )
    1218             $comment_author_email = $content_struct['author_email'];
    1219 
    1220         // We've got all the data -- post it:
    1221         $comment = compact('comment_ID', 'comment_content', 'comment_approved', 'comment_date', 'comment_date_gmt', 'comment_author', 'comment_author_email', 'comment_author_url');
    1222 
    1223         $result = wp_update_comment($comment);
    1224         if ( is_wp_error( $result ) )
    1225             return new IXR_Error(500, $result->get_error_message());
    1226 
    1227         if ( !$result )
    1228             return new IXR_Error(500, __('Sorry, the comment could not be edited. Something wrong happened.'));
    1229 
    1230         return true;
    1231     }
    1232 
    1233     /**
    1234      * Create new comment.
    1235      *
    1236      * @since 2.7.0
    1237      *
    1238      * @param array $args Method parameters.
    1239      * @return mixed {@link wp_new_comment()}
    1240      */
    1241     function wp_newComment($args) {
    1242         global $wpdb;
    1243 
    1244         $this->escape($args);
    1245 
    1246         $blog_id    = (int) $args[0];
    1247         $username   = $args[1];
    1248         $password   = $args[2];
    1249         $post       = $args[3];
    1250         $content_struct = $args[4];
    1251 
    1252         $allow_anon = apply_filters('xmlrpc_allow_anonymous_comments', false);
    1253 
    1254         $user = $this->login($username, $password);
    1255 
    1256         if ( !$user ) {
    1257             $logged_in = false;
    1258             if ( $allow_anon && get_option('comment_registration') )
    1259                 return new IXR_Error( 403, __( 'You must be registered to comment' ) );
    1260             else if ( !$allow_anon )
    1261                 return $this->error;
    1262         } else {
    1263             $logged_in = true;
    1264         }
    1265 
    1266         if ( is_numeric($post) )
    1267             $post_id = absint($post);
    1268         else
    1269             $post_id = url_to_postid($post);
    1270 
    1271         if ( ! $post_id )
    1272             return new IXR_Error( 404, __( 'Invalid post ID.' ) );
    1273 
    1274         if ( ! get_post($post_id) )
    1275             return new IXR_Error( 404, __( 'Invalid post ID.' ) );
    1276 
    1277         $comment['comment_post_ID'] = $post_id;
    1278 
    1279         if ( $logged_in ) {
    1280             $comment['comment_author'] = $wpdb->escape( $user->display_name );
    1281             $comment['comment_author_email'] = $wpdb->escape( $user->user_email );
    1282             $comment['comment_author_url'] = $wpdb->escape( $user->user_url );
    1283             $comment['user_ID'] = $user->ID;
    1284         } else {
    1285             $comment['comment_author'] = '';
    1286             if ( isset($content_struct['author']) )
    1287                 $comment['comment_author'] = $content_struct['author'];
    1288 
    1289             $comment['comment_author_email'] = '';
    1290             if ( isset($content_struct['author_email']) )
    1291                 $comment['comment_author_email'] = $content_struct['author_email'];
    1292 
    1293             $comment['comment_author_url'] = '';
    1294             if ( isset($content_struct['author_url']) )
    1295                 $comment['comment_author_url'] = $content_struct['author_url'];
    1296 
    1297             $comment['user_ID'] = 0;
    1298 
    1299             if ( get_option('require_name_email') ) {
    1300                 if ( 6 > strlen($comment['comment_author_email']) || '' == $comment['comment_author'] )
    1301                     return new IXR_Error( 403, __( 'Comment author name and email are required' ) );
    1302                 elseif ( !is_email($comment['comment_author_email']) )
    1303                     return new IXR_Error( 403, __( 'A valid email address is required' ) );
    1304             }
    1305         }
    1306 
    1307         $comment['comment_parent'] = isset($content_struct['comment_parent']) ? absint($content_struct['comment_parent']) : 0;
    1308 
    1309         $comment['comment_content'] = $content_struct['content'];
    1310 
    1311         do_action('xmlrpc_call', 'wp.newComment');
    1312 
    1313         return wp_new_comment($comment);
    1314     }
    1315 
    1316     /**
    1317      * Retrieve all of the comment status.
    1318      *
    1319      * @since 2.7.0
    1320      *
    1321      * @param array $args Method parameters.
    1322      * @return array
    1323      */
    1324     function wp_getCommentStatusList($args) {
    1325         $this->escape( $args );
    1326 
    1327         $blog_id    = (int) $args[0];
    1328         $username   = $args[1];
    1329         $password   = $args[2];
    1330 
    1331         if ( !$user = $this->login($username, $password) )
    1332             return $this->error;
    1333 
    1334         if ( !current_user_can( 'moderate_comments' ) )
    1335             return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
    1336 
    1337         do_action('xmlrpc_call', 'wp.getCommentStatusList');
    1338 
    1339         return get_comment_statuses( );
    1340     }
    1341 
    1342     /**
    1343      * Retrieve comment count.
    1344      *
    1345      * @since 2.5.0
    1346      *
    1347      * @param array $args Method parameters.
    1348      * @return array
    1349      */
    1350     function wp_getCommentCount( $args ) {
    1351         $this->escape($args);
    1352 
    1353         $blog_id    = (int) $args[0];
    1354         $username   = $args[1];
    1355         $password   = $args[2];
    1356         $post_id    = (int) $args[3];
    1357 
    1358         if ( !$user = $this->login($username, $password) )
    1359             return $this->error;
    1360 
    1361         if ( !current_user_can( 'edit_posts' ) )
    1362             return new IXR_Error( 403, __( 'You are not allowed access to details about comments.' ) );
    1363 
    1364         do_action('xmlrpc_call', 'wp.getCommentCount');
    1365 
    1366         $count = wp_count_comments( $post_id );
    1367         return array(
    1368             "approved" => $count->approved,
    1369             "awaiting_moderation" => $count->moderated,
    1370             "spam" => $count->spam,
    1371             "total_comments" => $count->total_comments
    1372         );
    1373     }
    1374 
    1375     /**
    1376      * Retrieve post statuses.
    1377      *
    1378      * @since 2.5.0
    1379      *
    1380      * @param array $args Method parameters.
    1381      * @return array
    1382      */
    1383     function wp_getPostStatusList( $args ) {
    1384         $this->escape( $args );
    1385 
    1386         $blog_id    = (int) $args[0];
    1387         $username   = $args[1];
    1388         $password   = $args[2];
    1389 
    1390         if ( !$user = $this->login($username, $password) )
    1391             return $this->error;
    1392 
    1393         if ( !current_user_can( 'edit_posts' ) )
    1394             return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
    1395 
    1396         do_action('xmlrpc_call', 'wp.getPostStatusList');
    1397 
    1398         return get_post_statuses( );
    1399     }
    1400 
    1401     /**
    1402      * Retrieve page statuses.
    1403      *
    1404      * @since 2.5.0
    1405      *
    1406      * @param array $args Method parameters.
    1407      * @return array
    1408      */
    1409     function wp_getPageStatusList( $args ) {
    1410         $this->escape( $args );
    1411 
    1412         $blog_id    = (int) $args[0];
    1413         $username   = $args[1];
    1414         $password   = $args[2];
    1415 
    1416         if ( !$user = $this->login($username, $password) )
    1417             return $this->error;
    1418 
    1419         if ( !current_user_can( 'edit_posts' ) )
    1420             return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
    1421 
    1422         do_action('xmlrpc_call', 'wp.getPageStatusList');
    1423 
    1424         return get_page_statuses( );
    1425     }
    1426 
    1427     /**
    1428      * Retrieve page templates.
    1429      *
    1430      * @since 2.6.0
    1431      *
    1432      * @param array $args Method parameters.
    1433      * @return array
    1434      */
    1435     function wp_getPageTemplates( $args ) {
    1436         $this->escape( $args );
    1437 
    1438         $blog_id    = (int) $args[0];
    1439         $username   = $args[1];
    1440         $password   = $args[2];
    1441 
    1442         if ( !$user = $this->login($username, $password) )
    1443             return $this->error;
    1444 
    1445         if ( !current_user_can( 'edit_pages' ) )
    1446             return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
    1447 
    1448         $templates = get_page_templates( );
    1449         $templates['Default'] = 'default';
    1450 
    1451         return $templates;
    1452     }
    1453 
    1454     /**
    1455      * Retrieve blog options.
    1456      *
    1457      * @since 2.6.0
    1458      *
    1459      * @param array $args Method parameters.
    1460      * @return array
    1461      */
    1462     function wp_getOptions( $args ) {
    1463         $this->escape( $args );
    1464 
    1465         $blog_id    = (int) $args[0];
    1466         $username   = $args[1];
    1467         $password   = $args[2];
    1468         $options    = (array) $args[3];
    1469 
    1470         if ( !$user = $this->login($username, $password) )
    1471             return $this->error;
    1472 
    1473         // If no specific options where asked for, return all of them
    1474         if ( count( $options ) == 0 )
    1475             $options = array_keys($this->blog_options);
    1476 
    1477         return $this->_getOptions($options);
    1478     }
    1479 
    1480     /**
    1481      * Retrieve blog options value from list.
    1482      *
    1483      * @since 2.6.0
    1484      *
    1485      * @param array $options Options to retrieve.
    1486      * @return array
    1487      */
    1488     function _getOptions($options) {
    1489         $data = array( );
    1490         foreach ( $options as $option ) {
    1491             if ( array_key_exists( $option, $this->blog_options ) ) {
    1492                 $data[$option] = $this->blog_options[$option];
    1493                 //Is the value static or dynamic?
    1494                 if ( isset( $data[$option]['option'] ) ) {
    1495                     $data[$option]['value'] = get_option( $data[$option]['option'] );
    1496                     unset($data[$option]['option']);
    1497                 }
    1498             }
    1499         }
    1500 
    1501         return $data;
    1502     }
    1503 
    1504     /**
    1505      * Update blog options.
    1506      *
    1507      * @since 2.6.0
    1508      *
    1509      * @param array $args Method parameters.
    1510      * @return unknown
    1511      */
    1512     function wp_setOptions( $args ) {
    1513         $this->escape( $args );
    1514 
    1515         $blog_id    = (int) $args[0];
    1516         $username   = $args[1];
    1517         $password   = $args[2];
    1518         $options    = (array) $args[3];
    1519 
    1520         if ( !$user = $this->login($username, $password) )
    1521             return $this->error;
    1522 
    1523         if ( !current_user_can( 'manage_options' ) )
    1524             return new IXR_Error( 403, __( 'You are not allowed to update options.' ) );
    1525 
    1526         foreach ( $options as $o_name => $o_value ) {
    1527             $option_names[] = $o_name;
    1528             if ( !array_key_exists( $o_name, $this->blog_options ) )
    1529                 continue;
    1530 
    1531             if ( $this->blog_options[$o_name]['readonly'] == true )
    1532                 continue;
    1533 
    1534             update_option( $this->blog_options[$o_name]['option'], $o_value );
    1535         }
    1536 
    1537         //Now return the updated values
    1538         return $this->_getOptions($option_names);
    1539     }
    1540 
    1541     /* Blogger API functions.
    1542      * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/
    1543      */
    1544 
    1545     /**
    1546      * Retrieve blogs that user owns.
    1547      *
    1548      * Will make more sense once we support multiple blogs.
    1549      *
    1550      * @since 1.5.0
    1551      *
    1552      * @param array $args Method parameters.
    1553      * @return array
    1554      */
    1555     function blogger_getUsersBlogs($args) {
    1556         if ( is_multisite() )
    1557             return $this->_multisite_getUsersBlogs($args);
    1558 
    1559         $this->escape($args);
    1560 
    1561         $username = $args[1];
    1562         $password  = $args[2];
    1563 
    1564         if ( !$user = $this->login($username, $password) )
    1565             return $this->error;
    1566 
    1567         do_action('xmlrpc_call', 'blogger.getUsersBlogs');
    1568 
    1569         $is_admin = current_user_can('manage_options');
    1570 
    1571         $struct = array(
    1572             'isAdmin'  => $is_admin,
    1573             'url'      => get_option('home') . '/',
    1574             'blogid'   => '1',
    1575             'blogName' => get_option('blogname'),
    1576             'xmlrpc'   => site_url( 'xmlrpc.php' )
    1577         );
    1578 
    1579         return array($struct);
    1580     }
    1581 
    1582     /**
    1583      * Private function for retrieving a users blogs for multisite setups
    1584      *
    1585      * @access protected
    1586      */
    1587     function _multisite_getUsersBlogs($args) {
    1588         global $current_blog;
    1589         $domain = $current_blog->domain;
    1590         $path = $current_blog->path . 'xmlrpc.php';
    1591         $protocol = is_ssl() ? 'https' : 'http';
    1592 
    1593         $rpc = new IXR_Client("$protocol://{$domain}{$path}");
    1594         $rpc->query('wp.getUsersBlogs', $args[1], $args[2]);
    1595         $blogs = $rpc->getResponse();
    1596 
    1597         if ( isset($blogs['faultCode']) )
    1598             return new IXR_Error($blogs['faultCode'], $blogs['faultString']);
    1599 
    1600         if ( $_SERVER['HTTP_HOST'] == $domain && $_SERVER['REQUEST_URI'] == $path ) {
    1601             return $blogs;
    1602         } else {
    1603             foreach ( (array) $blogs as $blog ) {
    1604                 if ( strpos($blog['url'], $_SERVER['HTTP_HOST']) )
    1605                     return array($blog);
    1606             }
    1607             return array();
    1608         }
    1609     }
    1610 
    1611     /**
    1612      * Retrieve user's data.
    1613      *
    1614      * Gives your client some info about you, so you don't have to.
    1615      *
    1616      * @since 1.5.0
    1617      *
    1618      * @param array $args Method parameters.
    1619      * @return array
    1620      */
    1621     function blogger_getUserInfo($args) {
    1622 
    1623         $this->escape($args);
    1624 
    1625         $username = $args[1];
    1626         $password  = $args[2];
    1627 
    1628         if ( !$user = $this->login($username, $password) )
    1629             return $this->error;
    1630 
    1631         if ( !current_user_can( 'edit_posts' ) )
    1632             return new IXR_Error( 401, __( 'Sorry, you do not have access to user data on this site.' ) );
    1633 
    1634         do_action('xmlrpc_call', 'blogger.getUserInfo');
    1635 
    1636         $struct = array(
    1637             'nickname'  => $user->nickname,
    1638             'userid'    => $user->ID,
    1639             'url'       => $user->user_url,
    1640             'lastname'  => $user->last_name,
    1641             'firstname' => $user->first_name
    1642         );
    1643 
    1644         return $struct;
    1645     }
    1646 
    1647     /**
    1648      * Retrieve post.
    1649      *
    1650      * @since 1.5.0
    1651      *
    1652      * @param array $args Method parameters.
    1653      * @return array
    1654      */
    1655     function blogger_getPost($args) {
    1656 
    1657         $this->escape($args);
    1658 
    1659         $post_ID    = (int) $args[1];
    1660         $username = $args[2];
    1661         $password  = $args[3];
    1662 
    1663         if ( !$user = $this->login($username, $password) )
    1664             return $this->error;
    1665 
    1666         if ( !current_user_can( 'edit_post', $post_ID ) )
    1667             return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
    1668 
    1669         do_action('xmlrpc_call', 'blogger.getPost');
    1670 
    1671         $post_data = wp_get_single_post($post_ID, ARRAY_A);
    1672 
    1673         $categories = implode(',', wp_get_post_categories($post_ID));
    1674 
    1675         $content  = '<title>'.stripslashes($post_data['post_title']).'</title>';
    1676         $content .= '<category>'.$categories.'</category>';
    1677         $content .= stripslashes($post_data['post_content']);
    1678 
    1679         $struct = array(
    1680             'userid'    => $post_data['post_author'],
    1681             'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'], false)),
    1682             'content'     => $content,
    1683             'postid'  => $post_data['ID']
    1684         );
    1685 
    1686         return $struct;
    1687     }
    1688 
    1689     /**
    1690      * Retrieve list of recent posts.
    1691      *
    1692      * @since 1.5.0
    1693      *
    1694      * @param array $args Method parameters.
    1695      * @return array
    1696      */
    1697     function blogger_getRecentPosts($args) {
    1698 
    1699         $this->escape($args);
    1700 
    1701         $blog_ID    = (int) $args[1]; /* though we don't use it yet */
    1702         $username = $args[2];
    1703         $password  = $args[3];
    1704         $num_posts  = $args[4];
    1705 
    1706         if ( !$user = $this->login($username, $password) )
    1707             return $this->error;
    1708 
    1709         do_action('xmlrpc_call', 'blogger.getRecentPosts');
    1710 
    1711         $posts_list = wp_get_recent_posts($num_posts);
    1712 
    1713         if ( !$posts_list ) {
    1714             $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
    1715             return $this->error;
    1716         }
    1717 
    1718         foreach ($posts_list as $entry) {
    1719             if ( !current_user_can( 'edit_post', $entry['ID'] ) )
    1720                 continue;
    1721 
    1722             $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false);
    1723             $categories = implode(',', wp_get_post_categories($entry['ID']));
    1724 
    1725             $content  = '<title>'.stripslashes($entry['post_title']).'</title>';
    1726             $content .= '<category>'.$categories.'</category>';
    1727             $content .= stripslashes($entry['post_content']);
    1728 
    1729             $struct[] = array(
    1730                 'userid' => $entry['post_author'],
    1731                 'dateCreated' => new IXR_Date($post_date),
    1732                 'content' => $content,
    1733                 'postid' => $entry['ID'],
    1734             );
    1735 
    1736         }
    1737 
    1738         $recent_posts = array();
    1739         for ( $j=0; $j<count($struct); $j++ ) {
    1740             array_push($recent_posts, $struct[$j]);
    1741         }
    1742 
    1743         return $recent_posts;
    1744     }
    1745 
    1746     /**
    1747      * Retrieve blog_filename content.
    1748      *
    1749      * @since 1.5.0
    1750      *
    1751      * @param array $args Method parameters.
    1752      * @return string
    1753      */
    1754     function blogger_getTemplate($args) {
    1755 
    1756         $this->escape($args);
    1757 
    1758         $blog_ID    = (int) $args[1];
    1759         $username = $args[2];
    1760         $password  = $args[3];
    1761         $template   = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */
    1762 
    1763         if ( !$user = $this->login($username, $password) )
    1764             return $this->error;
    1765 
    1766         do_action('xmlrpc_call', 'blogger.getTemplate');
    1767 
    1768         if ( !current_user_can('edit_themes') )
    1769             return new IXR_Error(401, __('Sorry, this user can not edit the template.'));
    1770 
    1771         /* warning: here we make the assumption that the blog's URL is on the same server */
    1772         $filename = get_option('home') . '/';
    1773         $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
    1774 
    1775         $f = fopen($filename, 'r');
    1776         $content = fread($f, filesize($filename));
    1777         fclose($f);
    1778 
    1779         /* so it is actually editable with a windows/mac client */
    1780         // 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);
    1781 
    1782         return $content;
    1783     }
    1784 
    1785     /**
    1786      * Updates the content of blog_filename.
    1787      *
    1788      * @since 1.5.0
    1789      *
    1790      * @param array $args Method parameters.
    1791      * @return bool True when done.
    1792      */
    1793     function blogger_setTemplate($args) {
    1794 
    1795         $this->escape($args);
    1796 
    1797         $blog_ID    = (int) $args[1];
    1798         $username = $args[2];
    1799         $password  = $args[3];
    1800         $content    = $args[4];
    1801         $template   = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */
    1802 
    1803         if ( !$user = $this->login($username, $password) )
    1804             return $this->error;
    1805 
    1806         do_action('xmlrpc_call', 'blogger.setTemplate');
    1807 
    1808         if ( !current_user_can('edit_themes') )
    1809             return new IXR_Error(401, __('Sorry, this user cannot edit the template.'));
    1810 
    1811         /* warning: here we make the assumption that the blog's URL is on the same server */
    1812         $filename = get_option('home') . '/';
    1813         $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
    1814 
    1815         if ($f = fopen($filename, 'w+')) {
    1816             fwrite($f, $content);
    1817             fclose($f);
    1818         } else {
    1819             return new IXR_Error(500, __('Either the file is not writable, or something wrong happened. The file has not been updated.'));
    1820         }
    1821 
    1822         return true;
    1823     }
    1824 
    1825     /**
    1826      * Create new post.
    1827      *
    1828      * @since 1.5.0
    1829      *
    1830      * @param array $args Method parameters.
    1831      * @return int
    1832      */
    1833     function blogger_newPost($args) {
    1834 
    1835         $this->escape($args);
    1836 
    1837         $blog_ID    = (int) $args[1]; /* though we don't use it yet */
    1838         $username = $args[2];
    1839         $password  = $args[3];
    1840         $content    = $args[4];
    1841         $publish    = $args[5];
    1842 
    1843         if ( !$user = $this->login($username, $password) )
    1844             return $this->error;
    1845 
    1846         do_action('xmlrpc_call', 'blogger.newPost');
    1847 
    1848         $cap = ($publish) ? 'publish_posts' : 'edit_posts';
    1849         if ( !current_user_can($cap) )
    1850             return new IXR_Error(401, __('Sorry, you are not allowed to post on this site.'));
    1851 
    1852         $post_status = ($publish) ? 'publish' : 'draft';
    1853 
    1854         $post_author = $user->ID;
    1855 
    1856         $post_title = xmlrpc_getposttitle($content);
    1857         $post_category = xmlrpc_getpostcategory($content);
    1858         $post_content = xmlrpc_removepostdata($content);
    1859 
    1860         $post_date = current_time('mysql');
    1861         $post_date_gmt = current_time('mysql', 1);
    1862 
    1863         $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status');
    1864 
    1865         $post_ID = wp_insert_post($post_data);
    1866         if ( is_wp_error( $post_ID ) )
    1867             return new IXR_Error(500, $post_ID->get_error_message());
    1868 
    1869         if ( !$post_ID )
    1870             return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
    1871 
    1872         $this->attach_uploads( $post_ID, $post_content );
    1873 
    1874         logIO('O', "Posted ! ID: $post_ID");
    1875 
    1876         return $post_ID;
    1877     }
    1878 
    1879     /**
    1880      * Edit a post.
    1881      *
    1882      * @since 1.5.0
    1883      *
    1884      * @param array $args Method parameters.
    1885      * @return bool true when done.
    1886      */
    1887     function blogger_editPost($args) {
    1888 
    1889         $this->escape($args);
    1890 
    1891         $post_ID     = (int) $args[1];
    1892         $username  = $args[2];
    1893         $password   = $args[3];
    1894         $content     = $args[4];
    1895         $publish     = $args[5];
    1896 
    1897         if ( !$user = $this->login($username, $password) )
    1898             return $this->error;
    1899 
    1900         do_action('xmlrpc_call', 'blogger.editPost');
    1901 
    1902         $actual_post = wp_get_single_post($post_ID,ARRAY_A);
    1903 
    1904         if ( !$actual_post || $actual_post['post_type'] != 'post' )
    1905             return new IXR_Error(404, __('Sorry, no such post.'));
    1906 
    1907         $this->escape($actual_post);
    1908 
    1909         if ( !current_user_can('edit_post', $post_ID) )
    1910             return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.'));
    1911 
    1912         extract($actual_post, EXTR_SKIP);
    1913 
    1914         if ( ('publish' == $post_status) && !current_user_can('publish_posts') )
    1915             return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
    1916 
    1917         $post_title = xmlrpc_getposttitle($content);
    1918         $post_category = xmlrpc_getpostcategory($content);
    1919         $post_content = xmlrpc_removepostdata($content);
    1920 
    1921         $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
    1922 
    1923         $result = wp_update_post($postdata);
    1924 
    1925         if ( !$result )
    1926             return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.'));
    1927 
    1928         $this->attach_uploads( $ID, $post_content );
    1929 
    1930         return true;
    1931     }
    1932 
    1933     /**
    1934      * Remove a post.
    1935      *
    1936      * @since 1.5.0
    1937      *
    1938      * @param array $args Method parameters.
    1939      * @return bool True when post is deleted.
    1940      */
    1941     function blogger_deletePost($args) {
    1942         $this->escape($args);
    1943 
    1944         $post_ID     = (int) $args[1];
    1945         $username  = $args[2];
    1946         $password   = $args[3];
    1947         $publish     = $args[4];
    1948 
    1949         if ( !$user = $this->login($username, $password) )
    1950             return $this->error;
    1951 
    1952         do_action('xmlrpc_call', 'blogger.deletePost');
    1953 
    1954         $actual_post = wp_get_single_post($post_ID,ARRAY_A);
    1955 
    1956         if ( !$actual_post || $actual_post['post_type'] != 'post' )
    1957             return new IXR_Error(404, __('Sorry, no such post.'));
    1958 
    1959         if ( !current_user_can('edit_post', $post_ID) )
    1960             return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.'));
    1961 
    1962         $result = wp_delete_post($post_ID);
    1963 
    1964         if ( !$result )
    1965             return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.'));
    1966 
    1967         return true;
    1968     }
    1969 
    1970     /* MetaWeblog API functions
    1971      * specs on wherever Dave Winer wants them to be
    1972      */
    1973 
    1974     /**
    1975      * Create a new post.
    1976      *
    1977      * @since 1.5.0
    1978      *
    1979      * @param array $args Method parameters.
    1980      * @return int
    1981      */
    1982     function mw_newPost($args) {
    1983         $this->escape($args);
    1984 
    1985         $blog_ID     = (int) $args[0]; // we will support this in the near future
    1986         $username  = $args[1];
    1987         $password   = $args[2];
    1988         $content_struct = $args[3];
    1989         $publish     = $args[4];
    1990 
    1991         if ( !$user = $this->login($username, $password) )
    1992             return $this->error;
    1993 
    1994         do_action('xmlrpc_call', 'metaWeblog.newPost');
    1995 
    1996         $cap = ( $publish ) ? 'publish_posts' : 'edit_posts';
    1997         $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
    1998         $post_type = 'post';
    1999         $page_template = '';
    2000         if ( !empty( $content_struct['post_type'] ) ) {
    2001             if ( $content_struct['post_type'] == 'page' ) {
    2002                 $cap = ( $publish ) ? 'publish_pages' : 'edit_pages';
    2003                 $error_message = __( 'Sorry, you are not allowed to publish pages on this site.' );
    2004                 $post_type = 'page';
    2005                 if ( !empty( $content_struct['wp_page_template'] ) )
    2006                     $page_template = $content_struct['wp_page_template'];
    2007             } elseif ( $content_struct['post_type'] == 'post' ) {
    2008                 // This is the default, no changes needed
    2009             } else {
    2010                 // No other post_type values are allowed here
    2011                 return new IXR_Error( 401, __( 'Invalid post type.' ) );
    2012             }
    2013         }
    2014 
    2015         if ( !current_user_can( $cap ) )
    2016             return new IXR_Error( 401, $error_message );
    2017 
    2018         // Let WordPress generate the post_name (slug) unless
    2019         // one has been provided.
    2020         $post_name = "";
    2021         if ( isset($content_struct["wp_slug"]) )
    2022             $post_name = $content_struct["wp_slug"];
    2023 
    2024         // Only use a password if one was given.
    2025         if ( isset($content_struct["wp_password"]) )
    2026             $post_password = $content_struct["wp_password"];
    2027 
    2028         // Only set a post parent if one was provided.
    2029         if ( isset($content_struct["wp_page_parent_id"]) )
    2030             $post_parent = $content_struct["wp_page_parent_id"];
    2031 
    2032         // Only set the menu_order if it was provided.
    2033         if ( isset($content_struct["wp_page_order"]) )
    2034             $menu_order = $content_struct["wp_page_order"];
    2035 
    2036         $post_author = $user->ID;
    2037 
    2038         // If an author id was provided then use it instead.
    2039         if ( isset($content_struct["wp_author_id"]) && ($user->ID != $content_struct["wp_author_id"]) ) {
    2040             switch ( $post_type ) {
    2041                 case "post":
    2042                     if ( !current_user_can("edit_others_posts") )
    2043                         return(new IXR_Error(401, __("You are not allowed to post as this user")));
    2044                     break;
    2045                 case "page":
    2046                     if ( !current_user_can("edit_others_pages") )
    2047                         return(new IXR_Error(401, __("You are not allowed to create pages as this user")));
    2048                     break;
    2049                 default:
    2050                     return(new IXR_Error(401, __("Invalid post type.")));
    2051                     break;
    2052             }
    2053             $post_author = $content_struct["wp_author_id"];
    2054         }
    2055 
    2056         $post_title = $content_struct['title'];
    2057         $post_content = $content_struct['description'];
    2058 
    2059         $post_status = $publish ? 'publish' : 'draft';
    2060 
    2061         if ( isset( $content_struct["{$post_type}_status"] ) ) {
    2062             switch ( $content_struct["{$post_type}_status"] ) {
    2063                 case 'draft':
    2064                 case 'private':
    2065                 case 'publish':
    2066                     $post_status = $content_struct["{$post_type}_status"];
    2067                     break;
    2068                 case 'pending':
    2069                     // Pending is only valid for posts, not pages.
    2070                     if ( $post_type === 'post' )
    2071                         $post_status = $content_struct["{$post_type}_status"];
    2072                     break;
    2073                 default:
    2074                     $post_status = $publish ? 'publish' : 'draft';
    2075                     break;
    2076             }
    2077         }
    2078 
    2079         $post_excerpt = $content_struct['mt_excerpt'];
    2080         $post_more = $content_struct['mt_text_more'];
    2081 
    2082         $tags_input = $content_struct['mt_keywords'];
    2083 
    2084         if ( isset($content_struct["mt_allow_comments"]) ) {
    2085             if ( !is_numeric($content_struct["mt_allow_comments"]) ) {
    2086                 switch ( $content_struct["mt_allow_comments"] ) {
    2087                     case "closed":
    2088                         $comment_status = "closed";
    2089                         break;
    2090                     case "open":
    2091                         $comment_status = "open";
    2092                         break;
    2093                     default:
    2094                         $comment_status = get_option("default_comment_status");
    2095                         break;
    2096                 }
    2097             } else {
    2098                 switch ( (int) $content_struct["mt_allow_comments"] ) {
    2099                     case 0:
    2100                     case 2:
    2101                         $comment_status = "closed";
    2102                         break;
    2103                     case 1:
    2104                         $comment_status = "open";
    2105                         break;
    2106                     default:
    2107                         $comment_status = get_option("default_comment_status");
    2108                         break;
    2109                 }
    2110             }
    2111         } else {
    2112             $comment_status = get_option("default_comment_status");
    2113         }
    2114 
    2115         if ( isset($content_struct["mt_allow_pings"]) ) {
    2116             if ( !is_numeric($content_struct["mt_allow_pings"]) ) {
    2117                 switch ( $content_struct['mt_allow_pings'] ) {
    2118                     case "closed":
    2119                         $ping_status = "closed";
    2120                         break;
    2121                     case "open":
    2122                         $ping_status = "open";
    2123                         break;
    2124                     default:
    2125                         $ping_status = get_option("default_ping_status");
    2126                         break;
    2127                 }
    2128             } else {
    2129                 switch ( (int) $content_struct["mt_allow_pings"] ) {
    2130                     case 0:
    2131                         $ping_status = "closed";
    2132                         break;
    2133                     case 1:
    2134                         $ping_status = "open";
    2135                         break;
    2136                     default:
    2137                         $ping_status = get_option("default_ping_status");
    2138                         break;
    2139                 }
    2140             }
    2141         } else {
    2142             $ping_status = get_option("default_ping_status");
    2143         }
    2144 
    2145         if ( $post_more )
    2146             $post_content = $post_content . "<!--more-->" . $post_more;
    2147 
    2148         $to_ping = $content_struct['mt_tb_ping_urls'];
    2149         if ( is_array($to_ping) )
    2150             $to_ping = implode(' ', $to_ping);
    2151 
    2152         // Do some timestamp voodoo
    2153         if ( !empty( $content_struct['date_created_gmt'] ) )
    2154             $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
    2155         elseif ( !empty( $content_struct['dateCreated']) )
    2156             $dateCreated = $content_struct['dateCreated']->getIso();
    2157 
    2158         if ( !empty( $dateCreated ) ) {
    2159             $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
    2160             $post_date_gmt = iso8601_to_datetime($dateCreated, GMT);
    2161         } else {
    2162             $post_date = current_time('mysql');
    2163             $post_date_gmt = current_time('mysql', 1);
    2164         }
    2165 
    2166         $catnames = $content_struct['categories'];
    2167         logIO('O', 'Post cats: ' . var_export($catnames,true));
    2168         $post_category = array();
    2169 
    2170         if ( is_array($catnames) ) {
    2171             foreach ($catnames as $cat) {
    2172                 $post_category[] = get_cat_ID($cat);
    2173             }
    2174         }
    2175 
    2176         // We've got all the data -- post it:
    2177         $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');
    2178 
    2179         $post_ID = wp_insert_post($postdata, true);
    2180         if ( is_wp_error( $post_ID ) )
    2181             return new IXR_Error(500, $post_ID->get_error_message());
    2182 
    2183         if ( !$post_ID )
    2184             return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
    2185 
    2186         // Only posts can be sticky
    2187         if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
    2188             if ( $content_struct['sticky'] == true )
    2189                 stick_post( $post_ID );
    2190             elseif ( $content_struct['sticky'] == false )
    2191                 unstick_post( $post_ID );
    2192         }
    2193 
    2194         if ( isset($content_struct['custom_fields']) )
    2195             $this->set_custom_fields($post_ID, $content_struct['custom_fields']);
    2196 
    2197         // Handle enclosures
    2198         $this->add_enclosure_if_new($post_ID, $content_struct['enclosure']);
    2199 
    2200         $this->attach_uploads( $post_ID, $post_content );
    2201 
    2202         logIO('O', "Posted ! ID: $post_ID");
    2203 
    2204         return strval($post_ID);
    2205     }
    2206 
    2207     function add_enclosure_if_new($post_ID, $enclosure) {
    2208         if ( is_array( $enclosure ) && isset( $enclosure['url'] ) && isset( $enclosure['length'] ) && isset( $enclosure['type'] ) ) {
    2209 
    2210             $encstring = $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type'];
    2211             $found = false;
    2212             foreach ( (array) get_post_custom($post_ID) as $key => $val) {
    2213                 if ($key == 'enclosure') {
    2214                     foreach ( (array) $val as $enc ) {
    2215                         if ($enc == $encstring) {
    2216                             $found = true;
    2217                             break 2;
    2218                         }
    2219                     }
    2220                 }
    2221             }
    2222             if (!$found)
    2223                 add_post_meta( $post_ID, 'enclosure', $encstring );
    2224         }
    2225     }
    2226 
    2227     /**
    2228      * Attach upload to a post.
    2229      *
    2230      * @since 2.1.0
    2231      *
    2232      * @param int $post_ID Post ID.
    2233      * @param string $post_content Post Content for attachment.
    2234      */
    2235     function attach_uploads( $post_ID, $post_content ) {
    2236         global $wpdb;
    2237 
    2238         // find any unattached files
    2239         $attachments = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts} WHERE post_parent = '0' AND post_type = 'attachment'" );
    2240         if ( is_array( $attachments ) ) {
    2241             foreach ( $attachments as $file ) {
    2242                 if ( strpos( $post_content, $file->guid ) !== false )
    2243                     $wpdb->update($wpdb->posts, array('post_parent' => $post_ID), array('ID' => $file->ID) );
    2244             }
    2245         }
    2246     }
    2247 
    2248     /**
    2249      * Edit a post.
    2250      *
    2251      * @since 1.5.0
    2252      *
    2253      * @param array $args Method parameters.
    2254      * @return bool True on success.
    2255      */
    2256     function mw_editPost($args) {
    2257 
    2258         $this->escape($args);
    2259 
    2260         $post_ID     = (int) $args[0];
    2261         $username  = $args[1];
    2262         $password   = $args[2];
    2263         $content_struct = $args[3];
    2264         $publish     = $args[4];
    2265 
    2266         if ( !$user = $this->login($username, $password) )
    2267             return $this->error;
    2268 
    2269         do_action('xmlrpc_call', 'metaWeblog.editPost');
    2270 
    2271         $cap = ( $publish ) ? 'publish_posts' : 'edit_posts';
    2272         $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
    2273         $post_type = 'post';
    2274         $page_template = '';
    2275         if ( !empty( $content_struct['post_type'] ) ) {
    2276             if ( $content_struct['post_type'] == 'page' ) {
    2277                 $cap = ( $publish ) ? 'publish_pages' : 'edit_pages';
    2278                 $error_message = __( 'Sorry, you are not allowed to publish pages on this site.' );
    2279                 $post_type = 'page';
    2280                 if ( !empty( $content_struct['wp_page_template'] ) )
    2281                     $page_template = $content_struct['wp_page_template'];
    2282             } elseif ( $content_struct['post_type'] == 'post' ) {
    2283                 // This is the default, no changes needed
    2284             } else {
    2285                 // No other post_type values are allowed here
    2286                 return new IXR_Error( 401, __( 'Invalid post type.' ) );
    2287             }
    2288         }
    2289 
    2290         if ( !current_user_can( $cap ) )
    2291             return new IXR_Error( 401, $error_message );
    2292 
    2293         $postdata = wp_get_single_post($post_ID, ARRAY_A);
    2294 
    2295         // If there is no post data for the give post id, stop
    2296         // now and return an error.  Other wise a new post will be
    2297         // created (which was the old behavior).
    2298         if ( empty($postdata["ID"]) )
    2299             return(new IXR_Error(404, __("Invalid post ID.")));
    2300 
    2301         $this->escape($postdata);
    2302         extract($postdata, EXTR_SKIP);
    2303 
    2304         // Let WordPress manage slug if none was provided.
    2305         $post_name = "";
    2306         if ( isset($content_struct["wp_slug"]) )
    2307             $post_name = $content_struct["wp_slug"];
    2308 
    2309         // Only use a password if one was given.
    2310         if ( isset($content_struct["wp_password"]) )
    2311             $post_password = $content_struct["wp_password"];
    2312 
    2313         // Only set a post parent if one was given.
    2314         if ( isset($content_struct["wp_page_parent_id"]) )
    2315             $post_parent = $content_struct["wp_page_parent_id"];
    2316 
    2317         // Only set the menu_order if it was given.
    2318         if ( isset($content_struct["wp_page_order"]) )
    2319             $menu_order = $content_struct["wp_page_order"];
    2320 
    2321         $post_author = $postdata["post_author"];
    2322 
    2323         // Only set the post_author if one is set.
    2324         if ( isset($content_struct["wp_author_id"]) && ($user->ID != $content_struct["wp_author_id"]) ) {
    2325             switch ( $post_type ) {
    2326                 case "post":
    2327                     if ( !current_user_can("edit_others_posts") )
    2328                         return(new IXR_Error(401, __("You are not allowed to change the post author as this user.")));
    2329                     break;
    2330                 case "page":
    2331                     if ( !current_user_can("edit_others_pages") )
    2332                         return(new IXR_Error(401, __("You are not allowed to change the page author as this user.")));
    2333                     break;
    2334                 default:
    2335                     return(new IXR_Error(401, __("Invalid post type.")));
    2336                     break;
    2337             }
    2338             $post_author = $content_struct["wp_author_id"];
    2339         }
    2340 
    2341         if ( isset($content_struct["mt_allow_comments"]) ) {
    2342             if ( !is_numeric($content_struct["mt_allow_comments"]) ) {
    2343                 switch ( $content_struct["mt_allow_comments"] ) {
    2344                     case "closed":
    2345                         $comment_status = "closed";
    2346                         break;
    2347                     case "open":
    2348                         $comment_status = "open";
    2349                         break;
    2350                     default:
    2351                         $comment_status = get_option("default_comment_status");
    2352                         break;
    2353                 }
    2354             } else {
    2355                 switch ( (int) $content_struct["mt_allow_comments"] ) {
    2356                     case 0:
    2357                     case 2:
    2358                         $comment_status = "closed";
    2359                         break;
    2360                     case 1:
    2361                         $comment_status = "open";
    2362                         break;
    2363                     default:
    2364                         $comment_status = get_option("default_comment_status");
    2365                         break;
    2366                 }
    2367             }
    2368         }
    2369 
    2370         if ( isset($content_struct["mt_allow_pings"]) ) {
    2371             if ( !is_numeric($content_struct["mt_allow_pings"]) ) {
    2372                 switch ( $content_struct["mt_allow_pings"] ) {
    2373                     case "closed":
    2374                         $ping_status = "closed";
    2375                         break;
    2376                     case "open":
    2377                         $ping_status = "open";
    2378                         break;
    2379                     default:
    2380                         $ping_status = get_option("default_ping_status");
    2381                         break;
    2382                 }
    2383             } else {
    2384                 switch ( (int) $content_struct["mt_allow_pings"] ) {
    2385                     case 0:
    2386                         $ping_status = "closed";
    2387                         break;
    2388                     case 1:
    2389                         $ping_status = "open";
    2390                         break;
    2391                     default:
    2392                         $ping_status = get_option("default_ping_status");
    2393                         break;
    2394                 }
    2395             }
    2396         }
    2397 
    2398         $post_title = $content_struct['title'];
    2399         $post_content = $content_struct['description'];
    2400         $catnames = $content_struct['categories'];
    2401 
    2402         $post_category = array();
    2403 
    2404         if ( is_array($catnames) ) {
    2405             foreach ($catnames as $cat) {
    2406                 $post_category[] = get_cat_ID($cat);
    2407             }
    2408         }
    2409 
    2410         $post_excerpt = $content_struct['mt_excerpt'];
    2411         $post_more = $content_struct['mt_text_more'];
    2412 
    2413         $post_status = $publish ? 'publish' : 'draft';
    2414         if ( isset( $content_struct["{$post_type}_status"] ) ) {
    2415             switch( $content_struct["{$post_type}_status"] ) {
    2416                 case 'draft':
    2417                 case 'private':
    2418                 case 'publish':
    2419                     $post_status = $content_struct["{$post_type}_status"];
    2420                     break;
    2421                 case 'pending':
    2422                     // Pending is only valid for posts, not pages.
    2423                     if ( $post_type === 'post' )
    2424                         $post_status = $content_struct["{$post_type}_status"];
    2425                     break;
    2426                 default:
    2427                     $post_status = $publish ? 'publish' : 'draft';
    2428                     break;
    2429             }
    2430         }
    2431 
    2432         $tags_input = $content_struct['mt_keywords'];
    2433 
    2434         if ( ('publish' == $post_status) ) {
    2435             if ( ( 'page' == $post_type ) && !current_user_can('publish_pages') )
    2436                 return new IXR_Error(401, __('Sorry, you do not have the right to publish this page.'));
    2437             else if ( !current_user_can('publish_posts') )
    2438                 return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
    2439         }
    2440 
    2441         if ( $post_more )
    2442             $post_content = $post_content . "<!--more-->" . $post_more;
    2443 
    2444         $to_ping = $content_struct['mt_tb_ping_urls'];
    2445         if ( is_array($to_ping) )
    2446             $to_ping = implode(' ', $to_ping);
    2447 
    2448         // Do some timestamp voodoo
    2449         if ( !empty( $content_struct['date_created_gmt'] ) )
    2450             $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
    2451         elseif ( !empty( $content_struct['dateCreated']) )
    2452             $dateCreated = $content_struct['dateCreated']->getIso();
    2453 
    2454         if ( !empty( $dateCreated ) ) {
    2455             $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
    2456             $post_date_gmt = iso8601_to_datetime($dateCreated, GMT);
    2457         } else {
    2458             $post_date     = $postdata['post_date'];
    2459             $post_date_gmt = $postdata['post_date_gmt'];
    2460         }
    2461 
    2462         // We've got all the data -- post it:
    2463         $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');
    2464 
    2465         $result = wp_update_post($newpost, true);
    2466         if ( is_wp_error( $result ) )
    2467             return new IXR_Error(500, $result->get_error_message());
    2468 
    2469         if ( !$result )
    2470             return new IXR_Error(500, __('Sorry, your entry could not be edited. Something wrong happened.'));
    2471 
    2472         // Only posts can be sticky
    2473         if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
    2474             if ( $content_struct['sticky'] == true )
    2475                 stick_post( $post_ID );
    2476             elseif ( $content_struct['sticky'] == false )
    2477                 unstick_post( $post_ID );
    2478         }
    2479 
    2480         if ( isset($content_struct['custom_fields']) )
    2481             $this->set_custom_fields($post_ID, $content_struct['custom_fields']);
    2482 
    2483         // Handle enclosures
    2484         $this->add_enclosure_if_new($post_ID, $content_struct['enclosure']);
    2485 
    2486         $this->attach_uploads( $ID, $post_content );
    2487 
    2488         logIO('O',"(MW) Edited ! ID: $post_ID");
    2489 
    2490         return true;
    2491     }
    2492 
    2493     /**
    2494      * Retrieve post.
    2495      *
    2496      * @since 1.5.0
    2497      *
    2498      * @param array $args Method parameters.
    2499      * @return array
    2500      */
    2501     function mw_getPost($args) {
    2502 
    2503         $this->escape($args);
    2504 
    2505         $post_ID     = (int) $args[0];
    2506         $username  = $args[1];
    2507         $password   = $args[2];
    2508 
    2509         if ( !$user = $this->login($username, $password) )
    2510             return $this->error;
    2511 
    2512         if ( !current_user_can( 'edit_post', $post_ID ) )
    2513             return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
    2514 
    2515         do_action('xmlrpc_call', 'metaWeblog.getPost');
    2516 
    2517         $postdata = wp_get_single_post($post_ID, ARRAY_A);
    2518 
    2519         if ($postdata['post_date'] != '') {
    2520             $post_date = mysql2date('Ymd\TH:i:s', $postdata['post_date'], false);
    2521             $post_date_gmt = mysql2date('Ymd\TH:i:s', $postdata['post_date_gmt'], false);
    2522 
    2523             // For drafts use the GMT version of the post date
    2524             if ( $postdata['post_status'] == 'draft' )
    2525                 $post_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $postdata['post_date'] ), 'Ymd\TH:i:s' );
    2526 
    2527             $categories = array();
    2528             $catids = wp_get_post_categories($post_ID);
    2529             foreach($catids as $catid)
    2530                 $categories[] = get_cat_name($catid);
    2531 
    2532             $tagnames = array();
    2533             $tags = wp_get_post_tags( $post_ID );
    2534             if ( !empty( $tags ) ) {
    2535                 foreach ( $tags as $tag )
    2536                     $tagnames[] = $tag->name;
    2537                 $tagnames = implode( ', ', $tagnames );
    2538             } else {
    2539                 $tagnames = '';
    2540             }
    2541 
    2542             $post = get_extended($postdata['post_content']);
    2543             $link = post_permalink($postdata['ID']);
    2544 
    2545             // Get the author info.
    2546             $author = get_userdata($postdata['post_author']);
    2547 
    2548             $allow_comments = ('open' == $postdata['comment_status']) ? 1 : 0;
    2549             $allow_pings = ('open' == $postdata['ping_status']) ? 1 : 0;
    2550 
    2551             // Consider future posts as published
    2552             if ( $postdata['post_status'] === 'future' )
    2553                 $postdata['post_status'] = 'publish';
    2554 
    2555             $sticky = false;
    2556             if ( is_sticky( $post_ID ) )
    2557                 $sticky = true;
    2558 
    2559             $enclosure = array();
    2560             foreach ( (array) get_post_custom($post_ID) as $key => $val) {
    2561                 if ($key == 'enclosure') {
    2562                     foreach ( (array) $val as $enc ) {
    2563                         $encdata = split("\n", $enc);
    2564                         $enclosure['url'] = trim(htmlspecialchars($encdata[0]));
    2565                         $enclosure['length'] = (int) trim($encdata[1]);
    2566                         $enclosure['type'] = trim($encdata[2]);
    2567                         break 2;
    2568                     }
    2569                 }
    2570             }
    2571 
    2572             $resp = array(
    2573                 'dateCreated' => new IXR_Date($post_date),
    2574                 'userid' => $postdata['post_author'],
    2575                 'postid' => $postdata['ID'],
    2576                 'description' => $post['main'],
    2577                 'title' => $postdata['post_title'],
    2578                 'link' => $link,
    2579                 'permaLink' => $link,
    2580                 // commented out because no other tool seems to use this
    2581                 //        'content' => $entry['post_content'],
    2582                 'categories' => $categories,
    2583                 'mt_excerpt' => $postdata['post_excerpt'],
    2584                 'mt_text_more' => $post['extended'],
    2585                 'mt_allow_comments' => $allow_comments,
    2586                 'mt_allow_pings' => $allow_pings,
    2587                 'mt_keywords' => $tagnames,
    2588                 'wp_slug' => $postdata['post_name'],
    2589                 'wp_password' => $postdata['post_password'],
    2590                 'wp_author_id' => $author->ID,
    2591                 'wp_author_display_name'    => $author->display_name,
    2592                 'date_created_gmt' => new IXR_Date($post_date_gmt),
    2593                 'post_status' => $postdata['post_status'],
    2594                 'custom_fields' => $this->get_custom_fields($post_ID),
    2595                 'sticky' => $sticky
    2596             );
    2597 
    2598             if ( !empty($enclosure) ) $resp['enclosure'] = $enclosure;
    2599 
    2600             return $resp;
    2601         } else {
    2602             return new IXR_Error(404, __('Sorry, no such post.'));
    2603         }
    2604     }
    2605 
    2606     /**
    2607      * Retrieve list of recent posts.
    2608      *
    2609      * @since 1.5.0
    2610      *
    2611      * @param array $args Method parameters.
    2612      * @return array
    2613      */
    2614     function mw_getRecentPosts($args) {
    2615 
    2616         $this->escape($args);
    2617 
    2618         $blog_ID     = (int) $args[0];
    2619         $username  = $args[1];
    2620         $password   = $args[2];
    2621         $num_posts   = (int) $args[3];
    2622 
    2623         if ( !$user = $this->login($username, $password) )
    2624             return $this->error;
    2625 
    2626         do_action('xmlrpc_call', 'metaWeblog.getRecentPosts');
    2627 
    2628         $posts_list = wp_get_recent_posts($num_posts);
    2629 
    2630         if ( !$posts_list )
    2631             return array( );
    2632 
    2633         foreach ($posts_list as $entry) {
    2634             if ( !current_user_can( 'edit_post', $entry['ID'] ) )
    2635                 continue;
    2636 
    2637             $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false);
    2638             $post_date_gmt = mysql2date('Ymd\TH:i:s', $entry['post_date_gmt'], false);
    2639 
    2640             // For drafts use the GMT version of the date
    2641             if ( $entry['post_status'] == 'draft' )
    2642                 $post_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $entry['post_date'] ), 'Ymd\TH:i:s' );
    2643 
    2644             $categories = array();
    2645             $catids = wp_get_post_categories($entry['ID']);
    2646             foreach( $catids as $catid )
    2647                 $categories[] = get_cat_name($catid);
    2648 
    2649             $tagnames = array();
    2650             $tags = wp_get_post_tags( $entry['ID'] );
    2651             if ( !empty( $tags ) ) {
    2652                 foreach ( $tags as $tag ) {
    2653                     $tagnames[] = $tag->name;
    2654                 }
    2655                 $tagnames = implode( ', ', $tagnames );
    2656             } else {
    2657                 $tagnames = '';
    2658             }
    2659 
    2660             $post = get_extended($entry['post_content']);
    2661             $link = post_permalink($entry['ID']);
    2662 
    2663             // Get the post author info.
    2664             $author = get_userdata($entry['post_author']);
    2665 
    2666             $allow_comments = ('open' == $entry['comment_status']) ? 1 : 0;
    2667             $allow_pings = ('open' == $entry['ping_status']) ? 1 : 0;
    2668 
    2669             // Consider future posts as published
    2670             if ( $entry['post_status'] === 'future' )
    2671                 $entry['post_status'] = 'publish';
    2672 
    2673             $struct[] = array(
    2674                 'dateCreated' => new IXR_Date($post_date),
    2675                 'userid' => $entry['post_author'],
    2676                 'postid' => $entry['ID'],
    2677                 'description' => $post['main'],
    2678                 'title' => $entry['post_title'],
    2679                 'link' => $link,
    2680                 'permaLink' => $link,
    2681                 // commented out because no other tool seems to use this
    2682                 // 'content' => $entry['post_content'],
    2683                 'categories' => $categories,
    2684                 'mt_excerpt' => $entry['post_excerpt'],
    2685                 'mt_text_more' => $post['extended'],
    2686                 'mt_allow_comments' => $allow_comments,
    2687                 'mt_allow_pings' => $allow_pings,
    2688                 'mt_keywords' => $tagnames,
    2689                 'wp_slug' => $entry['post_name'],
    2690                 'wp_password' => $entry['post_password'],
    2691                 'wp_author_id' => $author->ID,
    2692                 'wp_author_display_name' => $author->display_name,
    2693                 'date_created_gmt' => new IXR_Date($post_date_gmt),
    2694                 'post_status' => $entry['post_status'],
    2695                 'custom_fields' => $this->get_custom_fields($entry['ID'])
    2696             );
    2697 
    2698         }
    2699 
    2700         $recent_posts = array();
    2701         for ( $j=0; $j<count($struct); $j++ ) {
    2702             array_push($recent_posts, $struct[$j]);
    2703         }
    2704 
    2705         return $recent_posts;
    2706     }
    2707 
    2708     /**
    2709      * Retrieve the list of categories on a given blog.
    2710      *
    2711      * @since 1.5.0
    2712      *
    2713      * @param array $args Method parameters.
    2714      * @return array
    2715      */
    2716     function mw_getCategories($args) {
    2717 
    2718         $this->escape($args);
    2719 
    2720         $blog_ID     = (int) $args[0];
    2721         $username  = $args[1];
    2722         $password   = $args[2];
    2723 
    2724         if ( !$user = $this->login($username, $password) )
    2725             return $this->error;
    2726 
    2727         if ( !current_user_can( 'edit_posts' ) )
    2728             return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) );
    2729 
    2730         do_action('xmlrpc_call', 'metaWeblog.getCategories');
    2731 
    2732         $categories_struct = array();
    2733 
    2734         if ( $cats = get_categories(array('get' => 'all')) ) {
    2735             foreach ( $cats as $cat ) {
    2736                 $struct['categoryId'] = $cat->term_id;
    2737                 $struct['parentId'] = $cat->parent;
    2738                 $struct['description'] = $cat->name;
    2739                 $struct['categoryDescription'] = $cat->description;
    2740                 $struct['categoryName'] = $cat->name;
    2741                 $struct['htmlUrl'] = esc_html(get_category_link($cat->term_id));
    2742                 $struct['rssUrl'] = esc_html(get_category_feed_link($cat->term_id, 'rss2'));
    2743 
    2744                 $categories_struct[] = $struct;
    2745             }
    2746         }
    2747 
    2748         return $categories_struct;
    2749     }
    2750 
    2751     /**
    2752      * Uploads a file, following your settings.
    2753      *
    2754      * Adapted from a patch by Johann Richard.
    2755      *
    2756      * @link http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/
    2757      *
    2758      * @since 1.5.0
    2759      *
    2760      * @param array $args Method parameters.
    2761      * @return array
    2762      */
    2763     function mw_newMediaObject($args) {
    2764         global $wpdb;
    2765 
    2766         $blog_ID     = (int) $args[0];
    2767         $username  = $wpdb->escape($args[1]);
    2768         $password   = $wpdb->escape($args[2]);
    2769         $data        = $args[3];
    2770 
    2771         $name = sanitize_file_name( $data['name'] );
    2772         $type = $data['type'];
    2773         $bits = $data['bits'];
    2774 
    2775         logIO('O', '(MW) Received '.strlen($bits).' bytes');
    2776 
    2777         if ( !$user = $this->login($username, $password) )
    2778             return $this->error;
    2779 
    2780         do_action('xmlrpc_call', 'metaWeblog.newMediaObject');
    2781 
    2782         if ( !current_user_can('upload_files') ) {
    2783             logIO('O', '(MW) User does not have upload_files capability');
    2784             $this->error = new IXR_Error(401, __('You are not allowed to upload files to this site.'));
    2785             return $this->error;
    2786         }
    2787 
    2788         if ( $upload_err = apply_filters( "pre_upload_error", false ) )
    2789             return new IXR_Error(500, $upload_err);
    2790 
    2791         if ( !empty($data["overwrite"]) && ($data["overwrite"] == true) ) {
    2792             // Get postmeta info on the object.
    2793             $old_file = $wpdb->get_row("
    2794                 SELECT ID
    2795                 FROM {$wpdb->posts}
    2796                 WHERE post_title = '{$name}'
    2797                     AND post_type = 'attachment'
    2798             ");
    2799 
    2800             // Delete previous file.
    2801             wp_delete_attachment($old_file->ID);
    2802 
    2803             // Make sure the new name is different by pre-pending the
    2804             // previous post id.
    2805             $filename = preg_replace("/^wpid\d+-/", "", $name);
    2806             $name = "wpid{$old_file->ID}-{$filename}";
    2807         }
    2808 
    2809         $upload = wp_upload_bits($name, $type, $bits);
    2810         if ( ! empty($upload['error']) ) {
    2811             $errorString = sprintf(__('Could not write file %1$s (%2$s)'), $name, $upload['error']);
    2812             logIO('O', '(MW) ' . $errorString);
    2813             return new IXR_Error(500, $errorString);
    2814         }
    2815         // Construct the attachment array
    2816         // attach to post_id 0
    2817         $post_id = 0;
    2818         $attachment = array(
    2819             'post_title' => $name,
    2820             'post_content' => '',
    2821             'post_type' => 'attachment',
    2822             'post_parent' => $post_id,
    2823             'post_mime_type' => $type,
    2824             'guid' => $upload[ 'url' ]
    2825         );
    2826 
    2827         // Save the data
    2828         $id = wp_insert_attachment( $attachment, $upload[ 'file' ], $post_id );
    2829         wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );
    2830 
    2831         return apply_filters( 'wp_handle_upload', array( 'file' => $name, 'url' => $upload[ 'url' ], 'type' => $type ), 'upload' );
    2832     }
    2833 
    2834     /* MovableType API functions
    2835      * specs on http://www.movabletype.org/docs/mtmanual_programmatic.html
    2836      */
    2837 
    2838     /**
    2839      * Retrieve the post titles of recent posts.
    2840      *
    2841      * @since 1.5.0
    2842      *
    2843      * @param array $args Method parameters.
    2844      * @return array
    2845      */
    2846     function mt_getRecentPostTitles($args) {
    2847 
    2848         $this->escape($args);
    2849 
    2850         $blog_ID     = (int) $args[0];
    2851         $username  = $args[1];
    2852         $password   = $args[2];
    2853         $num_posts   = (int) $args[3];
    2854 
    2855         if ( !$user = $this->login($username, $password) )
    2856             return $this->error;
    2857 
    2858         do_action('xmlrpc_call', 'mt.getRecentPostTitles');
    2859 
    2860         $posts_list = wp_get_recent_posts($num_posts);
    2861 
    2862         if ( !$posts_list ) {
    2863             $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
    2864             return $this->error;
    2865         }
    2866 
    2867         foreach ($posts_list as $entry) {
    2868             if ( !current_user_can( 'edit_post', $entry['ID'] ) )
    2869                 continue;
    2870 
    2871             $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false);
    2872             $post_date_gmt = mysql2date('Ymd\TH:i:s', $entry['post_date_gmt'], false);
    2873 
    2874             // For drafts use the GMT version of the date
    2875             if ( $entry['post_status'] == 'draft' )
    2876                 $post_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $entry['post_date'] ), 'Ymd\TH:i:s' );
    2877 
    2878             $struct[] = array(
    2879                 'dateCreated' => new IXR_Date($post_date),
    2880                 'userid' => $entry['post_author'],
    2881                 'postid' => $entry['ID'],
    2882                 'title' => $entry['post_title'],
    2883                 'date_created_gmt' => new IXR_Date($post_date_gmt)
    2884             );
    2885 
    2886         }
    2887 
    2888         $recent_posts = array();
    2889         for ( $j=0; $j<count($struct); $j++ ) {
    2890             array_push($recent_posts, $struct[$j]);
    2891         }
    2892 
    2893         return $recent_posts;
    2894     }
    2895 
    2896     /**
    2897      * Retrieve list of all categories on blog.
    2898      *
    2899      * @since 1.5.0
    2900      *
    2901      * @param array $args Method parameters.
    2902      * @return array
    2903      */
    2904     function mt_getCategoryList($args) {
    2905 
    2906         $this->escape($args);
    2907 
    2908         $blog_ID     = (int) $args[0];
    2909         $username  = $args[1];
    2910         $password   = $args[2];
    2911 
    2912         if ( !$user = $this->login($username, $password) )
    2913             return $this->error;
    2914 
    2915         if ( !current_user_can( 'edit_posts' ) )
    2916             return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) );
    2917 
    2918         do_action('xmlrpc_call', 'mt.getCategoryList');
    2919 
    2920         $categories_struct = array();
    2921 
    2922         if ( $cats = get_categories(array('hide_empty' => 0, 'hierarchical' => 0)) ) {
    2923             foreach ( $cats as $cat ) {
    2924                 $struct['categoryId'] = $cat->term_id;
    2925                 $struct['categoryName'] = $cat->name;
    2926 
    2927                 $categories_struct[] = $struct;
    2928             }
    2929         }
    2930 
    2931         return $categories_struct;
    2932     }
    2933 
    2934     /**
    2935      * Retrieve post categories.
    2936      *
    2937      * @since 1.5.0
    2938      *
    2939      * @param array $args Method parameters.
    2940      * @return array
    2941      */
    2942     function mt_getPostCategories($args) {
    2943 
    2944         $this->escape($args);
    2945 
    2946         $post_ID     = (int) $args[0];
    2947         $username  = $args[1];
    2948         $password   = $args[2];
    2949 
    2950         if ( !$user = $this->login($username, $password) )
    2951             return $this->error;
    2952 
    2953         if ( !current_user_can( 'edit_post', $post_ID ) )
    2954             return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) );
    2955 
    2956         do_action('xmlrpc_call', 'mt.getPostCategories');
    2957 
    2958         $categories = array();
    2959         $catids = wp_get_post_categories(intval($post_ID));
    2960         // first listed category will be the primary category
    2961         $isPrimary = true;
    2962         foreach ( $catids as $catid ) {
    2963             $categories[] = array(
    2964                 'categoryName' => get_cat_name($catid),
    2965                 'categoryId' => (string) $catid,
    2966                 'isPrimary' => $isPrimary
    2967             );
    2968             $isPrimary = false;
    2969         }
    2970 
    2971         return $categories;
    2972     }
    2973 
    2974     /**
    2975      * Sets categories for a post.
    2976      *
    2977      * @since 1.5.0
    2978      *
    2979      * @param array $args Method parameters.
    2980      * @return bool True on success.
    2981      */
    2982     function mt_setPostCategories($args) {
    2983 
    2984         $this->escape($args);
    2985 
    2986         $post_ID     = (int) $args[0];
    2987         $username  = $args[1];
    2988         $password   = $args[2];
    2989         $categories  = $args[3];
    2990 
    2991         if ( !$user = $this->login($username, $password) )
    2992             return $this->error;
    2993 
    2994         do_action('xmlrpc_call', 'mt.setPostCategories');
    2995 
    2996         if ( !current_user_can('edit_post', $post_ID) )
    2997             return new IXR_Error(401, __('Sorry, you cannot edit this post.'));
    2998 
    2999         foreach ( $categories as $cat ) {
    3000             $catids[] = $cat['categoryId'];
    3001         }
    3002 
    3003         wp_set_post_categories($post_ID, $catids);
    3004 
    3005         return true;
    3006     }
    3007 
    3008     /**
    3009      * Retrieve an array of methods supported by this server.
    3010      *
    3011      * @since 1.5.0
    3012      *
    3013      * @param array $args Method parameters.
    3014      * @return array
    3015      */
    3016     function mt_supportedMethods($args) {
    3017 
    3018         do_action('xmlrpc_call', 'mt.supportedMethods');
    3019 
    3020         $supported_methods = array();
    3021         foreach ( $this->methods as $key => $value ) {
    3022             $supported_methods[] = $key;
    3023         }
    3024 
    3025         return $supported_methods;
    3026     }
    3027 
    3028     /**
    3029      * Retrieve an empty array because we don't support per-post text filters.
    3030      *
    3031      * @since 1.5.0
    3032      *
    3033      * @param array $args Method parameters.
    3034      */
    3035     function mt_supportedTextFilters($args) {
    3036         do_action('xmlrpc_call', 'mt.supportedTextFilters');
    3037         return apply_filters('xmlrpc_text_filters', array());
    3038     }
    3039 
    3040     /**
    3041      * Retrieve trackbacks sent to a given post.
    3042      *
    3043      * @since 1.5.0
    3044      *
    3045      * @param array $args Method parameters.
    3046      * @return mixed
    3047      */
    3048     function mt_getTrackbackPings($args) {
    3049 
    3050         global $wpdb;
    3051 
    3052         $post_ID = intval($args);
    3053 
    3054         do_action('xmlrpc_call', 'mt.getTrackbackPings');
    3055 
    3056         $actual_post = wp_get_single_post($post_ID, ARRAY_A);
    3057 
    3058         if ( !$actual_post )
    3059             return new IXR_Error(404, __('Sorry, no such post.'));
    3060 
    3061         $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) );
    3062 
    3063         if ( !$comments )
    3064             return array();
    3065 
    3066         $trackback_pings = array();
    3067         foreach ( $comments as $comment ) {
    3068             if ( 'trackback' == $comment->comment_type ) {
    3069                 $content = $comment->comment_content;
    3070                 $title = substr($content, 8, (strpos($content, '</strong>') - 8));
    3071                 $trackback_pings[] = array(
    3072                     'pingTitle' => $title,
    3073                     'pingURL'   => $comment->comment_author_url,
    3074                     'pingIP'    => $comment->comment_author_IP
    3075                 );
    3076             }
    3077         }
    3078 
    3079         return $trackback_pings;
    3080     }
    3081 
    3082     /**
    3083      * Sets a post's publish status to 'publish'.
    3084      *
    3085      * @since 1.5.0
    3086      *
    3087      * @param array $args Method parameters.
    3088      * @return int
    3089      */
    3090     function mt_publishPost($args) {
    3091 
    3092         $this->escape($args);
    3093 
    3094         $post_ID     = (int) $args[0];
    3095         $username  = $args[1];
    3096         $password   = $args[2];
    3097 
    3098         if ( !$user = $this->login($username, $password) )
    3099             return $this->error;
    3100 
    3101         do_action('xmlrpc_call', 'mt.publishPost');
    3102 
    3103         if ( !current_user_can('edit_post', $post_ID) )
    3104             return new IXR_Error(401, __('Sorry, you cannot edit this post.'));
    3105 
    3106         $postdata = wp_get_single_post($post_ID,ARRAY_A);
    3107 
    3108         $postdata['post_status'] = 'publish';
    3109 
    3110         // retain old cats
    3111         $cats = wp_get_post_categories($post_ID);
    3112         $postdata['post_category'] = $cats;
    3113         $this->escape($postdata);
    3114 
    3115         $result = wp_update_post($postdata);
    3116 
    3117         return $result;
    3118     }
    3119 
    3120     /* PingBack functions
    3121      * specs on www.hixie.ch/specs/pingback/pingback
    3122      */
    3123 
    3124     /**
    3125      * Retrieves a pingback and registers it.
    3126      *
    3127      * @since 1.5.0
    3128      *
    3129      * @param array $args Method parameters.
    3130      * @return array
    3131      */
    3132     function pingback_ping($args) {
    3133         global $wpdb;
    3134 
    3135         do_action('xmlrpc_call', 'pingback.ping');
    3136 
    3137         $this->escape($args);
    3138 
    3139         $pagelinkedfrom = $args[0];
    3140         $pagelinkedto   = $args[1];
    3141 
    3142         $title = '';
    3143 
    3144         $pagelinkedfrom = str_replace('&amp;', '&', $pagelinkedfrom);
    3145         $pagelinkedto = str_replace('&amp;', '&', $pagelinkedto);
    3146         $pagelinkedto = str_replace('&', '&amp;', $pagelinkedto);
    3147 
    3148         // Check if the page linked to is in our site
    3149         $pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home')));
    3150         if ( !$pos1 )
    3151             return new IXR_Error(0, __('Is there no link to us?'));
    3152 
    3153         // let's find which post is linked to
    3154         // FIXME: does url_to_postid() cover all these cases already?
    3155         //        if so, then let's use it and drop the old code.
    3156         $urltest = parse_url($pagelinkedto);
    3157         if ( $post_ID = url_to_postid($pagelinkedto) ) {
    3158             $way = 'url_to_postid()';
    3159         } elseif ( preg_match('#p/[0-9]{1,}#', $urltest['path'], $match) ) {
    3160             // the path defines the post_ID (archives/p/XXXX)
    3161             $blah = explode('/', $match[0]);
    3162             $post_ID = (int) $blah[1];
    3163             $way = 'from the path';
    3164         } elseif ( preg_match('#p=[0-9]{1,}#', $urltest['query'], $match) ) {
    3165             // the querystring defines the post_ID (?p=XXXX)
    3166             $blah = explode('=', $match[0]);
    3167             $post_ID = (int) $blah[1];
    3168             $way = 'from the querystring';
    3169         } elseif ( isset($urltest['fragment']) ) {
    3170             // an #anchor is there, it's either...
    3171             if ( intval($urltest['fragment']) ) {
    3172                 // ...an integer #XXXX (simpliest case)
    3173                 $post_ID = (int) $urltest['fragment'];
    3174                 $way = 'from the fragment (numeric)';
    3175             } elseif ( preg_match('/post-[0-9]+/',$urltest['fragment']) ) {
    3176                 // ...a post id in the form 'post-###'
    3177                 $post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']);
    3178                 $way = 'from the fragment (post-###)';
    3179             } elseif ( is_string($urltest['fragment']) ) {
    3180                 // ...or a string #title, a little more complicated
    3181                 $title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']);
    3182                 $sql = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title RLIKE %s", $title);
    3183                 if (! ($post_ID = $wpdb->get_var($sql)) ) {
    3184                     // returning unknown error '0' is better than die()ing
    3185                     return new IXR_Error(0, '');
    3186                 }
    3187                 $way = 'from the fragment (title)';
    3188             }
    3189         } else {
    3190             // TODO: Attempt to extract a post ID from the given URL
    3191             return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.'));
    3192         }
    3193         $post_ID = (int) $post_ID;
    3194 
    3195 
    3196         logIO("O","(PB) URL='$pagelinkedto' ID='$post_ID' Found='$way'");
    3197 
    3198         $post = get_post($post_ID);
    3199 
    3200         if ( !$post ) // Post_ID not found
    3201             return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.'));
    3202 
    3203         if ( $post_ID == url_to_postid($pagelinkedfrom) )
    3204             return new IXR_Error(0, __('The source URL and the target URL cannot both point to the same resource.'));
    3205 
    3206         // Check if pings are on
    3207         if ( !pings_open($post) )
    3208             return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.'));
    3209 
    3210         // Let's check that the remote site didn't already pingback this entry
    3211         if ( $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $post_ID, $pagelinkedfrom) ) )
    3212             return new IXR_Error( 48, __( 'The pingback has already been registered.' ) );
    3213 
    3214         // very stupid, but gives time to the 'from' server to publish !
    3215         sleep(1);
    3216 
    3217         // Let's check the remote site
    3218         $linea = wp_remote_fopen( $pagelinkedfrom );
    3219         if ( !$linea )
    3220             return new IXR_Error(16, __('The source URL does not exist.'));
    3221 
    3222         $linea = apply_filters('pre_remote_source', $linea, $pagelinkedto);
    3223 
    3224         // Work around bug in strip_tags():
    3225         $linea = str_replace('<!DOC', '<DOC', $linea);
    3226         $linea = preg_replace( '/[\s\r\n\t]+/', ' ', $linea ); // normalize spaces
    3227         $linea = preg_replace( "/ <(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $linea );
    3228 
    3229         preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle);
    3230         $title = $matchtitle[1];
    3231         if ( empty( $title ) )
    3232             return new IXR_Error(32, __('We cannot find a title on that page.'));
    3233 
    3234         $linea = strip_tags( $linea, '<a>' ); // just keep the tag we need
    3235 
    3236         $p = explode( "\n\n", $linea );
    3237 
    3238         $preg_target = preg_quote($pagelinkedto, '|');
    3239 
    3240         foreach ( $p as $para ) {
    3241             if ( strpos($para, $pagelinkedto) !== false ) { // it exists, but is it a link?
    3242                 preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context);
    3243 
    3244                 // If the URL isn't in a link context, keep looking
    3245                 if ( empty($context) )
    3246                     continue;
    3247 
    3248                 // We're going to use this fake tag to mark the context in a bit
    3249                 // the marker is needed in case the link text appears more than once in the paragraph
    3250                 $excerpt = preg_replace('|\</?wpcontext\>|', '', $para);
    3251 
    3252                 // prevent really long link text
    3253                 if ( strlen($context[1]) > 100 )
    3254                     $context[1] = substr($context[1], 0, 100) . '...';
    3255 
    3256                 $marker = '<wpcontext>'.$context[1].'</wpcontext>';    // set up our marker
    3257                 $excerpt= str_replace($context[0], $marker, $excerpt); // swap out the link for our marker
    3258                 $excerpt = strip_tags($excerpt, '<wpcontext>');        // strip all tags but our context marker
    3259                 $excerpt = trim($excerpt);
    3260                 $preg_marker = preg_quote($marker, '|');
    3261                 $excerpt = preg_replace("|.*?\s(.{0,100}$preg_marker.{0,100})\s.*|s", '$1', $excerpt);
    3262                 $excerpt = strip_tags($excerpt); // YES, again, to remove the marker wrapper
    3263                 break;
    3264             }
    3265         }
    3266 
    3267         if ( empty($context) ) // Link to target not found
    3268             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.'));
    3269 
    3270         $pagelinkedfrom = str_replace('&', '&amp;', $pagelinkedfrom);
    3271 
    3272         $context = '[...] ' . esc_html( $excerpt ) . ' [...]';
    3273         $pagelinkedfrom = $wpdb->escape( $pagelinkedfrom );
    3274 
    3275         $comment_post_ID = (int) $post_ID;
    3276         $comment_author = $title;
    3277         $this->escape($comment_author);
    3278         $comment_author_url = $pagelinkedfrom;
    3279         $comment_content = $context;
    3280         $this->escape($comment_content);
    3281         $comment_type = 'pingback';
    3282 
    3283         $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_content', 'comment_type');
    3284 
    3285         $comment_ID = wp_new_comment($commentdata);
    3286         do_action('pingback_post', $comment_ID);
    3287 
    3288         return sprintf(__('Pingback from %1$s to %2$s registered. Keep the web talking! :-)'), $pagelinkedfrom, $pagelinkedto);
    3289     }
    3290 
    3291     /**
    3292      * Retrieve array of URLs that pingbacked the given URL.
    3293      *
    3294      * Specs on http://www.aquarionics.com/misc/archives/blogite/0198.html
    3295      *
    3296      * @since 1.5.0
    3297      *
    3298      * @param array $args Method parameters.
    3299      * @return array
    3300      */
    3301     function pingback_extensions_getPingbacks($args) {
    3302 
    3303         global $wpdb;
    3304 
    3305         do_action('xmlrpc_call', 'pingback.extensions.getPingbacks');
    3306 
    3307         $this->escape($args);
    3308 
    3309         $url = $args;
    3310 
    3311         $post_ID = url_to_postid($url);
    3312         if ( !$post_ID ) {
    3313             // We aren't sure that the resource is available and/or pingback enabled
    3314             return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.'));
    3315         }
    3316 
    3317         $actual_post = wp_get_single_post($post_ID, ARRAY_A);
    3318 
    3319         if ( !$actual_post ) {
    3320             // No such post = resource not found
    3321             return new IXR_Error(32, __('The specified target URL does not exist.'));
    3322         }
    3323 
    3324         $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) );
    3325 
    3326         if ( !$comments )
    3327             return array();
    3328 
    3329         $pingbacks = array();
    3330         foreach ( $comments as $comment ) {
    3331             if ( 'pingback' == $comment->comment_type )
    3332                 $pingbacks[] = $comment->comment_author_url;
    3333         }
    3334 
    3335         return $pingbacks;
    3336     }
    3337 }
    3338 
    3339 $wp_xmlrpc_server = new wp_xmlrpc_server();
     105// Fire off the request
    3340106$wp_xmlrpc_server->serve_request();
    3341107?>
Note: See TracChangeset for help on using the changeset viewer.