[ XREF Home ] [ Index ]

PHP Cross Reference of WordPress Trunk

Provided by Yoast

title

Body

[close]

/wp-includes/ -> class-wp-xmlrpc-server.php (source)

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


Generated: Wed Jun 1 08:30:02 2011 Cross-referenced by PHPXref 0.7
Provided by Yoast and awesome WordPress Hosting