Make WordPress Core


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/xmlrpc.php

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