web/wp-includes/class-wp-xmlrpc-server.php
changeset 194 32102edaa81b
child 204 09a1c134465b
equal deleted inserted replaced
193:2f6f6f7551ca 194:32102edaa81b
       
     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 compatibility 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.newPost'			=> 'this:wp_newPost',
       
    40 			'wp.editPost'			=> 'this:wp_editPost',
       
    41 			'wp.deletePost'			=> 'this:wp_deletePost',
       
    42 			'wp.getPost'			=> 'this:wp_getPost',
       
    43 			'wp.getPosts'			=> 'this:wp_getPosts',
       
    44 			'wp.newTerm'			=> 'this:wp_newTerm',
       
    45 			'wp.editTerm'			=> 'this:wp_editTerm',
       
    46 			'wp.deleteTerm'			=> 'this:wp_deleteTerm',
       
    47 			'wp.getTerm'			=> 'this:wp_getTerm',
       
    48 			'wp.getTerms'			=> 'this:wp_getTerms',
       
    49 			'wp.getTaxonomy'		=> 'this:wp_getTaxonomy',
       
    50 			'wp.getTaxonomies'		=> 'this:wp_getTaxonomies',
       
    51 			'wp.getPage'			=> 'this:wp_getPage',
       
    52 			'wp.getPages'			=> 'this:wp_getPages',
       
    53 			'wp.newPage'			=> 'this:wp_newPage',
       
    54 			'wp.deletePage'			=> 'this:wp_deletePage',
       
    55 			'wp.editPage'			=> 'this:wp_editPage',
       
    56 			'wp.getPageList'		=> 'this:wp_getPageList',
       
    57 			'wp.getAuthors'			=> 'this:wp_getAuthors',
       
    58 			'wp.getCategories'		=> 'this:mw_getCategories',		// Alias
       
    59 			'wp.getTags'			=> 'this:wp_getTags',
       
    60 			'wp.newCategory'		=> 'this:wp_newCategory',
       
    61 			'wp.deleteCategory'		=> 'this:wp_deleteCategory',
       
    62 			'wp.suggestCategories'	=> 'this:wp_suggestCategories',
       
    63 			'wp.uploadFile'			=> 'this:mw_newMediaObject',	// Alias
       
    64 			'wp.getCommentCount'	=> 'this:wp_getCommentCount',
       
    65 			'wp.getPostStatusList'	=> 'this:wp_getPostStatusList',
       
    66 			'wp.getPageStatusList'	=> 'this:wp_getPageStatusList',
       
    67 			'wp.getPageTemplates'	=> 'this:wp_getPageTemplates',
       
    68 			'wp.getOptions'			=> 'this:wp_getOptions',
       
    69 			'wp.setOptions'			=> 'this:wp_setOptions',
       
    70 			'wp.getComment'			=> 'this:wp_getComment',
       
    71 			'wp.getComments'		=> 'this:wp_getComments',
       
    72 			'wp.deleteComment'		=> 'this:wp_deleteComment',
       
    73 			'wp.editComment'		=> 'this:wp_editComment',
       
    74 			'wp.newComment'			=> 'this:wp_newComment',
       
    75 			'wp.getCommentStatusList' => 'this:wp_getCommentStatusList',
       
    76 			'wp.getMediaItem'		=> 'this:wp_getMediaItem',
       
    77 			'wp.getMediaLibrary'	=> 'this:wp_getMediaLibrary',
       
    78 			'wp.getPostFormats'     => 'this:wp_getPostFormats',
       
    79 			'wp.getPostType'		=> 'this:wp_getPostType',
       
    80 			'wp.getPostTypes'		=> 'this:wp_getPostTypes',
       
    81 
       
    82 			// Blogger API
       
    83 			'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
       
    84 			'blogger.getUserInfo' => 'this:blogger_getUserInfo',
       
    85 			'blogger.getPost' => 'this:blogger_getPost',
       
    86 			'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
       
    87 			'blogger.getTemplate' => 'this:blogger_getTemplate',
       
    88 			'blogger.setTemplate' => 'this:blogger_setTemplate',
       
    89 			'blogger.newPost' => 'this:blogger_newPost',
       
    90 			'blogger.editPost' => 'this:blogger_editPost',
       
    91 			'blogger.deletePost' => 'this:blogger_deletePost',
       
    92 
       
    93 			// MetaWeblog API (with MT extensions to structs)
       
    94 			'metaWeblog.newPost' => 'this:mw_newPost',
       
    95 			'metaWeblog.editPost' => 'this:mw_editPost',
       
    96 			'metaWeblog.getPost' => 'this:mw_getPost',
       
    97 			'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
       
    98 			'metaWeblog.getCategories' => 'this:mw_getCategories',
       
    99 			'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
       
   100 
       
   101 			// MetaWeblog API aliases for Blogger API
       
   102 			// see http://www.xmlrpc.com/stories/storyReader$2460
       
   103 			'metaWeblog.deletePost' => 'this:blogger_deletePost',
       
   104 			'metaWeblog.getTemplate' => 'this:blogger_getTemplate',
       
   105 			'metaWeblog.setTemplate' => 'this:blogger_setTemplate',
       
   106 			'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
       
   107 
       
   108 			// MovableType API
       
   109 			'mt.getCategoryList' => 'this:mt_getCategoryList',
       
   110 			'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
       
   111 			'mt.getPostCategories' => 'this:mt_getPostCategories',
       
   112 			'mt.setPostCategories' => 'this:mt_setPostCategories',
       
   113 			'mt.supportedMethods' => 'this:mt_supportedMethods',
       
   114 			'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
       
   115 			'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
       
   116 			'mt.publishPost' => 'this:mt_publishPost',
       
   117 
       
   118 			// PingBack
       
   119 			'pingback.ping' => 'this:pingback_ping',
       
   120 			'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',
       
   121 
       
   122 			'demo.sayHello' => 'this:sayHello',
       
   123 			'demo.addTwoNumbers' => 'this:addTwoNumbers'
       
   124 		);
       
   125 
       
   126 		$this->initialise_blog_option_info();
       
   127 		$this->methods = apply_filters('xmlrpc_methods', $this->methods);
       
   128 	}
       
   129 
       
   130 	function serve_request() {
       
   131 		$this->IXR_Server($this->methods);
       
   132 	}
       
   133 
       
   134 	/**
       
   135 	 * Test XMLRPC API by saying, "Hello!" to client.
       
   136 	 *
       
   137 	 * @since 1.5.0
       
   138 	 *
       
   139 	 * @param array $args Method Parameters.
       
   140 	 * @return string
       
   141 	 */
       
   142 	function sayHello($args) {
       
   143 		return 'Hello!';
       
   144 	}
       
   145 
       
   146 	/**
       
   147 	 * Test XMLRPC API by adding two numbers for client.
       
   148 	 *
       
   149 	 * @since 1.5.0
       
   150 	 *
       
   151 	 * @param array $args Method Parameters.
       
   152 	 * @return int
       
   153 	 */
       
   154 	function addTwoNumbers($args) {
       
   155 		$number1 = $args[0];
       
   156 		$number2 = $args[1];
       
   157 		return $number1 + $number2;
       
   158 	}
       
   159 
       
   160 	/**
       
   161 	 * Check user's credentials.
       
   162 	 *
       
   163 	 * @since 1.5.0
       
   164 	 *
       
   165 	 * @param string $user_login User's username.
       
   166 	 * @param string $user_pass User's password.
       
   167 	 * @return bool Whether authentication passed.
       
   168 	 * @deprecated use wp_xmlrpc_server::login
       
   169 	 * @see wp_xmlrpc_server::login
       
   170 	 */
       
   171 	function login_pass_ok($user_login, $user_pass) {
       
   172 		if ( !get_option( 'enable_xmlrpc' ) ) {
       
   173 			$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') ) );
       
   174 			return false;
       
   175 		}
       
   176 
       
   177 		if (!user_pass_ok($user_login, $user_pass)) {
       
   178 			$this->error = new IXR_Error(403, __('Bad login/pass combination.'));
       
   179 			return false;
       
   180 		}
       
   181 		return true;
       
   182 	}
       
   183 
       
   184 	/**
       
   185 	 * Log user in.
       
   186 	 *
       
   187 	 * @since 2.8
       
   188 	 *
       
   189 	 * @param string $username User's username.
       
   190 	 * @param string $password User's password.
       
   191 	 * @return mixed WP_User object if authentication passed, false otherwise
       
   192 	 */
       
   193 	function login($username, $password) {
       
   194 		if ( !get_option( 'enable_xmlrpc' ) ) {
       
   195 			$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') ) );
       
   196 			return false;
       
   197 		}
       
   198 
       
   199 		$user = wp_authenticate($username, $password);
       
   200 
       
   201 		if (is_wp_error($user)) {
       
   202 			$this->error = new IXR_Error(403, __('Bad login/pass combination.'));
       
   203 			return false;
       
   204 		}
       
   205 
       
   206 		wp_set_current_user( $user->ID );
       
   207 		return $user;
       
   208 	}
       
   209 
       
   210 	/**
       
   211 	 * Sanitize string or array of strings for database.
       
   212 	 *
       
   213 	 * @since 1.5.2
       
   214 	 *
       
   215 	 * @param string|array $array Sanitize single string or array of strings.
       
   216 	 * @return string|array Type matches $array and sanitized for the database.
       
   217 	 */
       
   218 	function escape(&$array) {
       
   219 		global $wpdb;
       
   220 
       
   221 		if (!is_array($array)) {
       
   222 			return($wpdb->escape($array));
       
   223 		} else {
       
   224 			foreach ( (array) $array as $k => $v ) {
       
   225 				if ( is_array($v) ) {
       
   226 					$this->escape($array[$k]);
       
   227 				} else if ( is_object($v) ) {
       
   228 					//skip
       
   229 				} else {
       
   230 					$array[$k] = $wpdb->escape($v);
       
   231 				}
       
   232 			}
       
   233 		}
       
   234 	}
       
   235 
       
   236 	/**
       
   237 	 * Retrieve custom fields for post.
       
   238 	 *
       
   239 	 * @since 2.5.0
       
   240 	 *
       
   241 	 * @param int $post_id Post ID.
       
   242 	 * @return array Custom fields, if exist.
       
   243 	 */
       
   244 	function get_custom_fields($post_id) {
       
   245 		$post_id = (int) $post_id;
       
   246 
       
   247 		$custom_fields = array();
       
   248 
       
   249 		foreach ( (array) has_meta($post_id) as $meta ) {
       
   250 			// Don't expose protected fields.
       
   251 			if ( ! current_user_can( 'edit_post_meta', $post_id , $meta['meta_key'] ) )
       
   252 				continue;
       
   253 
       
   254 			$custom_fields[] = array(
       
   255 				"id"    => $meta['meta_id'],
       
   256 				"key"   => $meta['meta_key'],
       
   257 				"value" => $meta['meta_value']
       
   258 			);
       
   259 		}
       
   260 
       
   261 		return $custom_fields;
       
   262 	}
       
   263 
       
   264 	/**
       
   265 	 * Set custom fields for post.
       
   266 	 *
       
   267 	 * @since 2.5.0
       
   268 	 *
       
   269 	 * @param int $post_id Post ID.
       
   270 	 * @param array $fields Custom fields.
       
   271 	 */
       
   272 	function set_custom_fields($post_id, $fields) {
       
   273 		$post_id = (int) $post_id;
       
   274 
       
   275 		foreach ( (array) $fields as $meta ) {
       
   276 			if ( isset($meta['id']) ) {
       
   277 				$meta['id'] = (int) $meta['id'];
       
   278 				$pmeta = get_metadata_by_mid( 'post', $meta['id'] );
       
   279 				if ( isset($meta['key']) ) {
       
   280 					$meta['key'] = stripslashes( $meta['key'] );
       
   281 					if ( $meta['key'] != $pmeta->meta_key )
       
   282 						continue;
       
   283 					$meta['value'] = stripslashes_deep( $meta['value'] );
       
   284 					if ( current_user_can( 'edit_post_meta', $post_id, $meta['key'] ) )
       
   285 						update_metadata_by_mid( 'post', $meta['id'], $meta['value'] );
       
   286 				} elseif ( current_user_can( 'delete_post_meta', $post_id, $pmeta->meta_key ) ) {
       
   287 					delete_metadata_by_mid( 'post', $meta['id'] );
       
   288 				}
       
   289 			} elseif ( current_user_can( 'add_post_meta', $post_id, stripslashes( $meta['key'] ) ) ) {
       
   290 				add_post_meta( $post_id, $meta['key'], $meta['value'] );
       
   291 			}
       
   292 		}
       
   293 	}
       
   294 
       
   295 	/**
       
   296 	 * Set up blog options property.
       
   297 	 *
       
   298 	 * Passes property through 'xmlrpc_blog_options' filter.
       
   299 	 *
       
   300 	 * @since 2.6.0
       
   301 	 */
       
   302 	function initialise_blog_option_info() {
       
   303 		global $wp_version;
       
   304 
       
   305 		$this->blog_options = array(
       
   306 			// Read only options
       
   307 			'software_name'     => array(
       
   308 				'desc'          => __( 'Software Name' ),
       
   309 				'readonly'      => true,
       
   310 				'value'         => 'WordPress'
       
   311 			),
       
   312 			'software_version'  => array(
       
   313 				'desc'          => __( 'Software Version' ),
       
   314 				'readonly'      => true,
       
   315 				'value'         => $wp_version
       
   316 			),
       
   317 			'blog_url'          => array(
       
   318 				'desc'          => __( 'Site URL' ),
       
   319 				'readonly'      => true,
       
   320 				'option'        => 'siteurl'
       
   321 			),
       
   322 			'image_default_link_type' => array(
       
   323 				'desc'          => __( 'Image default link type' ),
       
   324 				'readonly'      => true,
       
   325 				'option'        => 'image_default_link_type'
       
   326 			),
       
   327 			'image_default_size' => array(
       
   328 				'desc'          => __( 'Image default size' ),
       
   329 				'readonly'      => true,
       
   330 				'option'        => 'image_default_size'
       
   331 			),
       
   332 			'image_default_align' => array(
       
   333 				'desc'          => __( 'Image default align' ),
       
   334 				'readonly'      => true,
       
   335 				'option'        => 'image_default_align'
       
   336 			),
       
   337 			'template'          => array(
       
   338 				'desc'          => __( 'Template' ),
       
   339 				'readonly'      => true,
       
   340 				'option'        => 'template'
       
   341 			),
       
   342 			'stylesheet'        => array(
       
   343 				'desc'          => __( 'Stylesheet' ),
       
   344 				'readonly'      => true,
       
   345 				'option'        => 'stylesheet'
       
   346 			),
       
   347 			'post_thumbnail'    => array(
       
   348 				'desc'          => __('Post Thumbnail'),
       
   349 				'readonly'      => true,
       
   350 				'value'         => current_theme_supports( 'post-thumbnails' )
       
   351 			),
       
   352 
       
   353 			// Updatable options
       
   354 			'time_zone'         => array(
       
   355 				'desc'          => __( 'Time Zone' ),
       
   356 				'readonly'      => false,
       
   357 				'option'        => 'gmt_offset'
       
   358 			),
       
   359 			'blog_title'        => array(
       
   360 				'desc'          => __( 'Site Title' ),
       
   361 				'readonly'      => false,
       
   362 				'option'        => 'blogname'
       
   363 			),
       
   364 			'blog_tagline'      => array(
       
   365 				'desc'          => __( 'Site Tagline' ),
       
   366 				'readonly'      => false,
       
   367 				'option'        => 'blogdescription'
       
   368 			),
       
   369 			'date_format'       => array(
       
   370 				'desc'          => __( 'Date Format' ),
       
   371 				'readonly'      => false,
       
   372 				'option'        => 'date_format'
       
   373 			),
       
   374 			'time_format'       => array(
       
   375 				'desc'          => __( 'Time Format' ),
       
   376 				'readonly'      => false,
       
   377 				'option'        => 'time_format'
       
   378 			),
       
   379 			'users_can_register' => array(
       
   380 				'desc'          => __( 'Allow new users to sign up' ),
       
   381 				'readonly'      => false,
       
   382 				'option'        => 'users_can_register'
       
   383 			),
       
   384 			'thumbnail_size_w'  => array(
       
   385 				'desc'          => __( 'Thumbnail Width' ),
       
   386 				'readonly'      => false,
       
   387 				'option'        => 'thumbnail_size_w'
       
   388 			),
       
   389 			'thumbnail_size_h'  => array(
       
   390 				'desc'          => __( 'Thumbnail Height' ),
       
   391 				'readonly'      => false,
       
   392 				'option'        => 'thumbnail_size_h'
       
   393 			),
       
   394 			'thumbnail_crop'    => array(
       
   395 				'desc'          => __( 'Crop thumbnail to exact dimensions' ),
       
   396 				'readonly'      => false,
       
   397 				'option'        => 'thumbnail_crop'
       
   398 			),
       
   399 			'medium_size_w'     => array(
       
   400 				'desc'          => __( 'Medium size image width' ),
       
   401 				'readonly'      => false,
       
   402 				'option'        => 'medium_size_w'
       
   403 			),
       
   404 			'medium_size_h'     => array(
       
   405 				'desc'          => __( 'Medium size image height' ),
       
   406 				'readonly'      => false,
       
   407 				'option'        => 'medium_size_h'
       
   408 			),
       
   409 			'large_size_w'      => array(
       
   410 				'desc'          => __( 'Large size image width' ),
       
   411 				'readonly'      => false,
       
   412 				'option'        => 'large_size_w'
       
   413 			),
       
   414 			'large_size_h'      => array(
       
   415 				'desc'          => __( 'Large size image height' ),
       
   416 				'readonly'      => false,
       
   417 				'option'        => 'large_size_h'
       
   418 			),
       
   419 			'default_comment_status' => array(
       
   420 				'desc'          => __( 'Allow people to post comments on new articles' ),
       
   421 				'readonly'      => false,
       
   422 				'option'        => 'default_comment_status'
       
   423 			),
       
   424 			'default_ping_status' => array(
       
   425 				'desc'          => __( 'Allow link notifications from other blogs (pingbacks and trackbacks)' ),
       
   426 				'readonly'      => false,
       
   427 				'option'        => 'default_ping_status'
       
   428 			)
       
   429 		);
       
   430 
       
   431 		$this->blog_options = apply_filters( 'xmlrpc_blog_options', $this->blog_options );
       
   432 	}
       
   433 
       
   434 	/**
       
   435 	 * Retrieve the blogs of the user.
       
   436 	 *
       
   437 	 * @since 2.6.0
       
   438 	 *
       
   439 	 * @param array $args Method parameters. Contains:
       
   440 	 *  - username
       
   441 	 *  - password
       
   442 	 * @return array. Contains:
       
   443 	 *  - 'isAdmin'
       
   444 	 *  - 'url'
       
   445 	 *  - 'blogid'
       
   446 	 *  - 'blogName'
       
   447 	 *  - 'xmlrpc' - url of xmlrpc endpoint
       
   448 	 */
       
   449 	function wp_getUsersBlogs( $args ) {
       
   450 		global $current_site;
       
   451 		// If this isn't on WPMU then just use blogger_getUsersBlogs
       
   452 		if ( !is_multisite() ) {
       
   453 			array_unshift( $args, 1 );
       
   454 			return $this->blogger_getUsersBlogs( $args );
       
   455 		}
       
   456 
       
   457 		$this->escape( $args );
       
   458 
       
   459 		$username = $args[0];
       
   460 		$password = $args[1];
       
   461 
       
   462 		if ( !$user = $this->login($username, $password) )
       
   463 			return $this->error;
       
   464 
       
   465 		do_action( 'xmlrpc_call', 'wp.getUsersBlogs' );
       
   466 
       
   467 		$blogs = (array) get_blogs_of_user( $user->ID );
       
   468 		$struct = array();
       
   469 
       
   470 		foreach ( $blogs as $blog ) {
       
   471 			// Don't include blogs that aren't hosted at this site
       
   472 			if ( $blog->site_id != $current_site->id )
       
   473 				continue;
       
   474 
       
   475 			$blog_id = $blog->userblog_id;
       
   476 			switch_to_blog($blog_id);
       
   477 			$is_admin = current_user_can('manage_options');
       
   478 
       
   479 			$struct[] = array(
       
   480 				'isAdmin'		=> $is_admin,
       
   481 				'url'			=> get_option( 'home' ) . '/',
       
   482 				'blogid'		=> (string) $blog_id,
       
   483 				'blogName'		=> get_option( 'blogname' ),
       
   484 				'xmlrpc'		=> site_url( 'xmlrpc.php' )
       
   485 			);
       
   486 
       
   487 			restore_current_blog();
       
   488 		}
       
   489 
       
   490 		return $struct;
       
   491 	}
       
   492 
       
   493 	/**
       
   494 	 * Checks if the method received at least the minimum number of arguments.
       
   495 	 *
       
   496 	 * @since 3.4.0
       
   497 	 *
       
   498 	 * @param string|array $args Sanitize single string or array of strings.
       
   499 	 * @param int $count Minimum number of arguments.
       
   500 	 * @return boolean if $args contains at least $count arguments.
       
   501 	 */
       
   502 	protected function minimum_args( $args, $count ) {
       
   503 		if ( count( $args ) < $count ) {
       
   504 			$this->error = new IXR_Error( 400, __( 'Insufficient arguments passed to this XML-RPC method.' ) );
       
   505 			return false;
       
   506 		}
       
   507 
       
   508 		return true;
       
   509 	}
       
   510 
       
   511 	/**
       
   512 	 * Prepares taxonomy data for return in an XML-RPC object.
       
   513 	 *
       
   514 	 * @access protected
       
   515 	 *
       
   516 	 * @param object $taxonomy The unprepared taxonomy data
       
   517 	 * @param array $fields The subset of taxonomy fields to return
       
   518 	 * @return array The prepared taxonomy data
       
   519 	 */
       
   520 	protected function _prepare_taxonomy( $taxonomy, $fields ) {
       
   521 		$_taxonomy = array(
       
   522 			'name' => $taxonomy->name,
       
   523 			'label' => $taxonomy->label,
       
   524 			'hierarchical' => (bool) $taxonomy->hierarchical,
       
   525 			'public' => (bool) $taxonomy->public,
       
   526 			'show_ui' => (bool) $taxonomy->show_ui,
       
   527 			'_builtin' => (bool) $taxonomy->_builtin,
       
   528 		);
       
   529 
       
   530 		if ( in_array( 'labels', $fields ) )
       
   531 			$_taxonomy['labels'] = (array) $taxonomy->labels;
       
   532 
       
   533 		if ( in_array( 'cap', $fields ) )
       
   534 			$_taxonomy['cap'] = (array) $taxonomy->cap;
       
   535 
       
   536 		if ( in_array( 'object_type', $fields ) )
       
   537 			$_taxonomy['object_type'] = array_unique( (array) $taxonomy->object_type );
       
   538 
       
   539 		return apply_filters( 'xmlrpc_prepare_taxonomy', $_taxonomy, $taxonomy, $fields );
       
   540 	}
       
   541 
       
   542 	/**
       
   543 	 * Prepares term data for return in an XML-RPC object.
       
   544 	 *
       
   545 	 * @access protected
       
   546 	 *
       
   547 	 * @param array|object $term The unprepared term data
       
   548 	 * @return array The prepared term data
       
   549 	 */
       
   550 	protected function _prepare_term( $term ) {
       
   551 		$_term = $term;
       
   552 		if ( ! is_array( $_term) )
       
   553 			$_term = get_object_vars( $_term );
       
   554 
       
   555 		// For Intergers which may be largeer than XMLRPC supports ensure we return strings.
       
   556 		$_term['term_id'] = strval( $_term['term_id'] );
       
   557 		$_term['term_group'] = strval( $_term['term_group'] );
       
   558 		$_term['term_taxonomy_id'] = strval( $_term['term_taxonomy_id'] );
       
   559 		$_term['parent'] = strval( $_term['parent'] );
       
   560 
       
   561 		// Count we are happy to return as an Integer because people really shouldn't use Terms that much.
       
   562 		$_term['count'] = intval( $_term['count'] );
       
   563 
       
   564 		return apply_filters( 'xmlrpc_prepare_term', $_term, $term );
       
   565 	}
       
   566 
       
   567 	/**
       
   568 	 * Convert a WordPress date string to an IXR_Date object.
       
   569 	 *
       
   570 	 * @access protected
       
   571 	 *
       
   572 	 * @param string $date
       
   573 	 * @return IXR_Date
       
   574 	 */
       
   575 	protected function _convert_date( $date ) {
       
   576 		if ( $date === '0000-00-00 00:00:00' ) {
       
   577 			return new IXR_Date( '00000000T00:00:00Z' );
       
   578 		}
       
   579 		return new IXR_Date( mysql2date( 'Ymd\TH:i:s', $date, false ) );
       
   580 	}
       
   581 
       
   582 	/**
       
   583 	 * Convert a WordPress GMT date string to an IXR_Date object.
       
   584 	 *
       
   585 	 * @access protected
       
   586 	 *
       
   587 	 * @param string $date_gmt
       
   588 	 * @param string $date
       
   589 	 * @return IXR_Date
       
   590 	 */
       
   591 	protected function _convert_date_gmt( $date_gmt, $date ) {
       
   592 		if ( $date !== '0000-00-00 00:00:00' && $date_gmt === '0000-00-00 00:00:00' ) {
       
   593 			return new IXR_Date( get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $date, false ), 'Ymd\TH:i:s' ) );
       
   594 		}
       
   595 		return $this->_convert_date( $date_gmt );
       
   596 	}
       
   597 
       
   598 	/**
       
   599 	 * Prepares post data for return in an XML-RPC object.
       
   600 	 *
       
   601 	 * @access protected
       
   602 	 *
       
   603 	 * @param array $post The unprepared post data
       
   604 	 * @param array $fields The subset of post type fields to return
       
   605 	 * @return array The prepared post data
       
   606 	 */
       
   607 	protected function _prepare_post( $post, $fields ) {
       
   608 		// holds the data for this post. built up based on $fields
       
   609 		$_post = array( 'post_id' => strval( $post['ID'] ) );
       
   610 
       
   611 		// prepare common post fields
       
   612 		$post_fields = array(
       
   613 			'post_title'        => $post['post_title'],
       
   614 			'post_date'         => $this->_convert_date( $post['post_date'] ),
       
   615 			'post_date_gmt'     => $this->_convert_date_gmt( $post['post_date_gmt'], $post['post_date'] ),
       
   616 			'post_modified'     => $this->_convert_date( $post['post_modified'] ),
       
   617 			'post_modified_gmt' => $this->_convert_date_gmt( $post['post_modified_gmt'], $post['post_modified'] ),
       
   618 			'post_status'       => $post['post_status'],
       
   619 			'post_type'         => $post['post_type'],
       
   620 			'post_name'         => $post['post_name'],
       
   621 			'post_author'       => $post['post_author'],
       
   622 			'post_password'     => $post['post_password'],
       
   623 			'post_excerpt'      => $post['post_excerpt'],
       
   624 			'post_content'      => $post['post_content'],
       
   625 			'post_parent'       => strval( $post['post_parent'] ),
       
   626 			'post_mime_type'    => $post['post_mime_type'],
       
   627 			'link'              => post_permalink( $post['ID'] ),
       
   628 			'guid'              => $post['guid'],
       
   629 			'menu_order'        => intval( $post['menu_order'] ),
       
   630 			'comment_status'    => $post['comment_status'],
       
   631 			'ping_status'       => $post['ping_status'],
       
   632 			'sticky'            => ( $post['post_type'] === 'post' && is_sticky( $post['ID'] ) ),
       
   633 		);
       
   634 
       
   635 		// Thumbnail
       
   636 		$post_fields['post_thumbnail'] = array();
       
   637 		$thumbnail_id = get_post_thumbnail_id( $post['ID'] );
       
   638 		if ( $thumbnail_id ) {
       
   639 			$thumbnail_size = current_theme_supports('post-thumbnail') ? 'post-thumbnail' : 'thumbnail';
       
   640 			$post_fields['post_thumbnail'] = $this->_prepare_media_item( get_post( $thumbnail_id ), $thumbnail_size );
       
   641 		}
       
   642 
       
   643 		// Consider future posts as published
       
   644 		if ( $post_fields['post_status'] === 'future' )
       
   645 			$post_fields['post_status'] = 'publish';
       
   646 
       
   647 		// Fill in blank post format
       
   648 		$post_fields['post_format'] = get_post_format( $post['ID'] );
       
   649 		if ( empty( $post_fields['post_format'] ) )
       
   650 			$post_fields['post_format'] = 'standard';
       
   651 
       
   652 		// Merge requested $post_fields fields into $_post
       
   653 		if ( in_array( 'post', $fields ) ) {
       
   654 			$_post = array_merge( $_post, $post_fields );
       
   655 		} else {
       
   656 			$requested_fields = array_intersect_key( $post_fields, array_flip( $fields ) );
       
   657 			$_post = array_merge( $_post, $requested_fields );
       
   658 		}
       
   659 
       
   660 		$all_taxonomy_fields = in_array( 'taxonomies', $fields );
       
   661 
       
   662 		if ( $all_taxonomy_fields || in_array( 'terms', $fields ) ) {
       
   663 			$post_type_taxonomies = get_object_taxonomies( $post['post_type'], 'names' );
       
   664 			$terms = wp_get_object_terms( $post['ID'], $post_type_taxonomies );
       
   665 			$_post['terms'] = array();
       
   666 			foreach ( $terms as $term ) {
       
   667 				$_post['terms'][] = $this->_prepare_term( $term );
       
   668 			}
       
   669 		}
       
   670 
       
   671 		if ( in_array( 'custom_fields', $fields ) )
       
   672 			$_post['custom_fields'] = $this->get_custom_fields( $post['ID'] );
       
   673 
       
   674 		if ( in_array( 'enclosure', $fields ) ) {
       
   675 			$_post['enclosure'] = array();
       
   676 			$enclosures = (array) get_post_meta( $post['ID'], 'enclosure' );
       
   677 			if ( ! empty( $enclosures ) ) {
       
   678 				$encdata = explode( "\n", $enclosures[0] );
       
   679 				$_post['enclosure']['url'] = trim( htmlspecialchars( $encdata[0] ) );
       
   680 				$_post['enclosure']['length'] = (int) trim( $encdata[1] );
       
   681 				$_post['enclosure']['type'] = trim( $encdata[2] );
       
   682 			}
       
   683 		}
       
   684 
       
   685 		return apply_filters( 'xmlrpc_prepare_post', $_post, $post, $fields );
       
   686 	}
       
   687 
       
   688 	/**
       
   689 	 * Prepares post data for return in an XML-RPC object.
       
   690 	 *
       
   691 	 * @access protected
       
   692 	 *
       
   693 	 * @param object $post_type Post type object
       
   694 	 * @param array $fields The subset of post fields to return
       
   695 	 * @return array The prepared post type data
       
   696 	 */
       
   697 	protected function _prepare_post_type( $post_type, $fields ) {
       
   698 		$_post_type = array(
       
   699 			'name' => $post_type->name,
       
   700 			'label' => $post_type->label,
       
   701 			'hierarchical' => (bool) $post_type->hierarchical,
       
   702 			'public' => (bool) $post_type->public,
       
   703 			'show_ui' => (bool) $post_type->show_ui,
       
   704 			'_builtin' => (bool) $post_type->_builtin,
       
   705 			'has_archive' => (bool) $post_type->has_archive,
       
   706 			'supports' => get_all_post_type_supports( $post_type->name ),
       
   707 		);
       
   708 
       
   709 		if ( in_array( 'labels', $fields ) ) {
       
   710 			$_post_type['labels'] = (array) $post_type->labels;
       
   711 		}
       
   712 
       
   713 		if ( in_array( 'cap', $fields ) ) {
       
   714 			$_post_type['cap'] = (array) $post_type->cap;
       
   715 			$_post_type['map_meta_cap'] = (bool) $post_type->map_meta_cap;
       
   716 		}
       
   717 
       
   718 		if ( in_array( 'menu', $fields ) ) {
       
   719 			$_post_type['menu_position'] = (int) $post_type->menu_position;
       
   720 			$_post_type['menu_icon'] = $post_type->menu_icon;
       
   721 			$_post_type['show_in_menu'] = (bool) $post_type->show_in_menu;
       
   722 		}
       
   723 
       
   724 		if ( in_array( 'taxonomies', $fields ) )
       
   725 			$_post_type['taxonomies'] = get_object_taxonomies( $post_type->name, 'names' );
       
   726 
       
   727 		return apply_filters( 'xmlrpc_prepare_post_type', $_post_type, $post_type );
       
   728 	}
       
   729 
       
   730 	/**
       
   731 	 * Prepares media item data for return in an XML-RPC object.
       
   732 	 *
       
   733 	 * @access protected
       
   734 	 *
       
   735 	 * @param object $media_item The unprepared media item data
       
   736 	 * @param string $thumbnail_size The image size to use for the thumbnail URL
       
   737 	 * @return array The prepared media item data
       
   738 	 */
       
   739 	protected function _prepare_media_item( $media_item, $thumbnail_size = 'thumbnail' ) {
       
   740 		$_media_item = array(
       
   741 			'attachment_id'    => strval( $media_item->ID ),
       
   742 			'date_created_gmt' => $this->_convert_date_gmt( $media_item->post_date_gmt, $media_item->post_date ),
       
   743 			'parent'           => $media_item->post_parent,
       
   744 			'link'             => wp_get_attachment_url( $media_item->ID ),
       
   745 			'title'            => $media_item->post_title,
       
   746 			'caption'          => $media_item->post_excerpt,
       
   747 			'description'      => $media_item->post_content,
       
   748 			'metadata'         => wp_get_attachment_metadata( $media_item->ID ),
       
   749 		);
       
   750 
       
   751 		$thumbnail_src = image_downsize( $media_item->ID, $thumbnail_size );
       
   752 		if ( $thumbnail_src )
       
   753 			$_media_item['thumbnail'] = $thumbnail_src[0];
       
   754 		else
       
   755 			$_media_item['thumbnail'] = $_media_item['link'];
       
   756 
       
   757 		return apply_filters( 'xmlrpc_prepare_media_item', $_media_item, $media_item, $thumbnail_size );
       
   758 	}
       
   759 
       
   760 	/**
       
   761 	 * Prepares page data for return in an XML-RPC object.
       
   762 	 *
       
   763 	 * @access protected
       
   764 	 *
       
   765 	 * @param object $page The unprepared page data
       
   766 	 * @return array The prepared page data
       
   767 	 */
       
   768 	protected function _prepare_page( $page ) {
       
   769 		// Get all of the page content and link.
       
   770 		$full_page = get_extended( $page->post_content );
       
   771 		$link = post_permalink( $page->ID );
       
   772 
       
   773 		// Get info the page parent if there is one.
       
   774 		$parent_title = "";
       
   775 		if ( ! empty( $page->post_parent ) ) {
       
   776 			$parent = get_page( $page->post_parent );
       
   777 			$parent_title = $parent->post_title;
       
   778 		}
       
   779 
       
   780 		// Determine comment and ping settings.
       
   781 		$allow_comments = comments_open( $page->ID ) ? 1 : 0;
       
   782 		$allow_pings = pings_open( $page->ID ) ? 1 : 0;
       
   783 
       
   784 		// Format page date.
       
   785 		$page_date = $this->_convert_date( $page->post_date );
       
   786 		$page_date_gmt = $this->_convert_date_gmt( $page->post_date_gmt, $page->post_date );
       
   787 
       
   788 		// Pull the categories info together.
       
   789 		$categories = array();
       
   790 		foreach ( wp_get_post_categories( $page->ID ) as $cat_id ) {
       
   791 			$categories[] = get_cat_name( $cat_id );
       
   792 		}
       
   793 
       
   794 		// Get the author info.
       
   795 		$author = get_userdata( $page->post_author );
       
   796 
       
   797 		$page_template = get_page_template_slug( $page->ID );
       
   798 		if ( empty( $page_template ) )
       
   799 			$page_template = 'default';
       
   800 
       
   801 		$_page = array(
       
   802 			'dateCreated'            => $page_date,
       
   803 			'userid'                 => $page->post_author,
       
   804 			'page_id'                => $page->ID,
       
   805 			'page_status'            => $page->post_status,
       
   806 			'description'            => $full_page['main'],
       
   807 			'title'                  => $page->post_title,
       
   808 			'link'                   => $link,
       
   809 			'permaLink'              => $link,
       
   810 			'categories'             => $categories,
       
   811 			'excerpt'                => $page->post_excerpt,
       
   812 			'text_more'              => $full_page['extended'],
       
   813 			'mt_allow_comments'      => $allow_comments,
       
   814 			'mt_allow_pings'         => $allow_pings,
       
   815 			'wp_slug'                => $page->post_name,
       
   816 			'wp_password'            => $page->post_password,
       
   817 			'wp_author'              => $author->display_name,
       
   818 			'wp_page_parent_id'      => $page->post_parent,
       
   819 			'wp_page_parent_title'   => $parent_title,
       
   820 			'wp_page_order'          => $page->menu_order,
       
   821 			'wp_author_id'           => (string) $author->ID,
       
   822 			'wp_author_display_name' => $author->display_name,
       
   823 			'date_created_gmt'       => $page_date_gmt,
       
   824 			'custom_fields'          => $this->get_custom_fields( $page->ID ),
       
   825 			'wp_page_template'       => $page_template
       
   826 		);
       
   827 
       
   828 		return apply_filters( 'xmlrpc_prepare_page', $_page, $page );
       
   829 	}
       
   830 
       
   831 	/**
       
   832 	 * Prepares comment data for return in an XML-RPC object.
       
   833 	 *
       
   834 	 * @access protected
       
   835 	 *
       
   836 	 * @param object $comment The unprepared comment data
       
   837 	 * @return array The prepared comment data
       
   838 	 */
       
   839 	protected function _prepare_comment( $comment ) {
       
   840 		// Format page date.
       
   841 		$comment_date = $this->_convert_date( $comment->comment_date );
       
   842 		$comment_date_gmt = $this->_convert_date_gmt( $comment->comment_date_gmt, $comment->comment_date );
       
   843 
       
   844 		if ( '0' == $comment->comment_approved )
       
   845 			$comment_status = 'hold';
       
   846 		else if ( 'spam' == $comment->comment_approved )
       
   847 			$comment_status = 'spam';
       
   848 		else if ( '1' == $comment->comment_approved )
       
   849 			$comment_status = 'approve';
       
   850 		else
       
   851 			$comment_status = $comment->comment_approved;
       
   852 
       
   853 		$_comment = array(
       
   854 			'date_created_gmt' => $comment_date_gmt,
       
   855 			'user_id'          => $comment->user_id,
       
   856 			'comment_id'       => $comment->comment_ID,
       
   857 			'parent'           => $comment->comment_parent,
       
   858 			'status'           => $comment_status,
       
   859 			'content'          => $comment->comment_content,
       
   860 			'link'             => get_comment_link($comment),
       
   861 			'post_id'          => $comment->comment_post_ID,
       
   862 			'post_title'       => get_the_title($comment->comment_post_ID),
       
   863 			'author'           => $comment->comment_author,
       
   864 			'author_url'       => $comment->comment_author_url,
       
   865 			'author_email'     => $comment->comment_author_email,
       
   866 			'author_ip'        => $comment->comment_author_IP,
       
   867 			'type'             => $comment->comment_type,
       
   868 		);
       
   869 
       
   870 		return apply_filters( 'xmlrpc_prepare_comment', $_comment, $comment );
       
   871 	}
       
   872 
       
   873 	/**
       
   874 	 * Create a new post for any registered post type.
       
   875 	 *
       
   876 	 * @since 3.4.0
       
   877 	 *
       
   878 	 * @param array $args Method parameters. Contains:
       
   879 	 *  - int     $blog_id
       
   880 	 *  - string  $username
       
   881 	 *  - string  $password
       
   882 	 *  - array   $content_struct
       
   883 	 *      $content_struct can contain:
       
   884 	 *      - post_type (default: 'post')
       
   885 	 *      - post_status (default: 'draft')
       
   886 	 *      - post_title
       
   887 	 *      - post_author
       
   888 	 *      - post_exerpt
       
   889 	 *      - post_content
       
   890 	 *      - post_date_gmt | post_date
       
   891 	 *      - post_format
       
   892 	 *      - post_password
       
   893 	 *      - comment_status - can be 'open' | 'closed'
       
   894 	 *      - ping_status - can be 'open' | 'closed'
       
   895 	 *      - sticky
       
   896 	 *      - post_thumbnail - ID of a media item to use as the post thumbnail/featured image
       
   897 	 *      - custom_fields - array, with each element containing 'key' and 'value'
       
   898 	 *      - terms - array, with taxonomy names as keys and arrays of term IDs as values
       
   899 	 *      - terms_names - array, with taxonomy names as keys and arrays of term names as values
       
   900 	 *      - enclosure
       
   901 	 *      - any other fields supported by wp_insert_post()
       
   902 	 * @return string post_id
       
   903 	 */
       
   904 	function wp_newPost( $args ) {
       
   905 		if ( ! $this->minimum_args( $args, 4 ) )
       
   906 			return $this->error;
       
   907 
       
   908 		$this->escape( $args );
       
   909 
       
   910 		$blog_id        = (int) $args[0];
       
   911 		$username       = $args[1];
       
   912 		$password       = $args[2];
       
   913 		$content_struct = $args[3];
       
   914 
       
   915 		if ( ! $user = $this->login( $username, $password ) )
       
   916 			return $this->error;
       
   917 
       
   918 		do_action( 'xmlrpc_call', 'wp.newPost' );
       
   919 
       
   920 		unset( $content_struct['ID'] );
       
   921 
       
   922 		return $this->_insert_post( $user, $content_struct );
       
   923 	}
       
   924 
       
   925 	/**
       
   926 	 * Helper method for filtering out elements from an array.
       
   927 	 *
       
   928 	 * @since 3.4.0
       
   929 	 *
       
   930 	 * @param int $count Number to compare to one.
       
   931 	 */
       
   932 	private function _is_greater_than_one( $count ) {
       
   933 		return $count > 1;
       
   934 	}
       
   935 
       
   936 	/**
       
   937 	 * Helper method for wp_newPost and wp_editPost, containing shared logic.
       
   938 	 *
       
   939 	 * @since 3.4.0
       
   940 	 * @uses wp_insert_post()
       
   941 	 *
       
   942 	 * @param WP_User $user The post author if post_author isn't set in $content_struct.
       
   943 	 * @param array $content_struct Post data to insert.
       
   944 	 */
       
   945 	protected function _insert_post( $user, $content_struct ) {
       
   946 		$defaults = array( 'post_status' => 'draft', 'post_type' => 'post', 'post_author' => 0,
       
   947 			'post_password' => '', 'post_excerpt' => '', 'post_content' => '', 'post_title' => '' );
       
   948 
       
   949 		$post_data = wp_parse_args( $content_struct, $defaults );
       
   950 
       
   951 		$post_type = get_post_type_object( $post_data['post_type'] );
       
   952 		if ( ! $post_type )
       
   953 			return new IXR_Error( 403, __( 'Invalid post type' ) );
       
   954 
       
   955 		$update = ! empty( $post_data['ID'] );
       
   956 
       
   957 		if ( $update ) {
       
   958 			if ( ! get_post( $post_data['ID'] ) )
       
   959 				return new IXR_Error( 401, __( 'Invalid post ID.' ) );
       
   960 			if ( ! current_user_can( $post_type->cap->edit_post, $post_data['ID'] ) )
       
   961 				return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit this post.' ) );
       
   962 			if ( $post_data['post_type'] != get_post_type( $post_data['ID'] ) )
       
   963 				return new IXR_Error( 401, __( 'The post type may not be changed.' ) );
       
   964 		} else {
       
   965 			if ( ! current_user_can( $post_type->cap->edit_posts ) )
       
   966 				return new IXR_Error( 401, __( 'Sorry, you are not allowed to post on this site.' ) );
       
   967 		}
       
   968 
       
   969 		switch ( $post_data['post_status'] ) {
       
   970 			case 'draft':
       
   971 			case 'pending':
       
   972 				break;
       
   973 			case 'private':
       
   974 				if ( ! current_user_can( $post_type->cap->publish_posts ) )
       
   975 					return new IXR_Error( 401, __( 'Sorry, you are not allowed to create private posts in this post type' ) );
       
   976 				break;
       
   977 			case 'publish':
       
   978 			case 'future':
       
   979 				if ( ! current_user_can( $post_type->cap->publish_posts ) )
       
   980 					return new IXR_Error( 401, __( 'Sorry, you are not allowed to publish posts in this post type' ) );
       
   981 				break;
       
   982 			default:
       
   983 				$post_data['post_status'] = 'draft';
       
   984 			break;
       
   985 		}
       
   986 
       
   987 		if ( ! empty( $post_data['post_password'] ) && ! current_user_can( $post_type->cap->publish_posts ) )
       
   988 			return new IXR_Error( 401, __( 'Sorry, you are not allowed to create password protected posts in this post type' ) );
       
   989 
       
   990 		$post_data['post_author'] = absint( $post_data['post_author'] );
       
   991 		if ( ! empty( $post_data['post_author'] ) && $post_data['post_author'] != $user->ID ) {
       
   992 			if ( ! current_user_can( $post_type->cap->edit_others_posts ) )
       
   993 				return new IXR_Error( 401, __( 'You are not allowed to create posts as this user.' ) );
       
   994 
       
   995 			$author = get_userdata( $post_data['post_author'] );
       
   996 
       
   997 			if ( ! $author )
       
   998 				return new IXR_Error( 404, __( 'Invalid author ID.' ) );
       
   999 		} else {
       
  1000 			$post_data['post_author'] = $user->ID;
       
  1001 		}
       
  1002 
       
  1003 		if ( isset( $post_data['comment_status'] ) && $post_data['comment_status'] != 'open' && $post_data['comment_status'] != 'closed' )
       
  1004 			unset( $post_data['comment_status'] );
       
  1005 
       
  1006 		if ( isset( $post_data['ping_status'] ) && $post_data['ping_status'] != 'open' && $post_data['ping_status'] != 'closed' )
       
  1007 			unset( $post_data['ping_status'] );
       
  1008 
       
  1009 		// Do some timestamp voodoo
       
  1010 		if ( ! empty( $post_data['post_date_gmt'] ) ) {
       
  1011 			// We know this is supposed to be GMT, so we're going to slap that Z on there by force
       
  1012 			$dateCreated = rtrim( $post_data['post_date_gmt']->getIso(), 'Z' ) . 'Z';
       
  1013 		} elseif ( ! empty( $post_data['post_date'] ) ) {
       
  1014 			$dateCreated = $post_data['post_date']->getIso();
       
  1015 		}
       
  1016 
       
  1017 		if ( ! empty( $dateCreated ) ) {
       
  1018 			$post_data['post_date'] = get_date_from_gmt( iso8601_to_datetime( $dateCreated ) );
       
  1019 			$post_data['post_date_gmt'] = iso8601_to_datetime( $dateCreated, 'GMT' );
       
  1020 		}
       
  1021 
       
  1022 		if ( ! isset( $post_data['ID'] ) )
       
  1023 			$post_data['ID'] = get_default_post_to_edit( $post_data['post_type'], true )->ID;
       
  1024 		$post_ID = $post_data['ID'];
       
  1025 
       
  1026 		if ( $post_data['post_type'] == 'post' ) {
       
  1027 			// Private and password-protected posts cannot be stickied.
       
  1028 			if ( $post_data['post_status'] == 'private' || ! empty( $post_data['post_password'] ) ) {
       
  1029 				// Error if the client tried to stick the post, otherwise, silently unstick.
       
  1030 				if ( ! empty( $post_data['sticky'] ) )
       
  1031 					return new IXR_Error( 401, __( 'Sorry, you cannot stick a private post.' ) );
       
  1032 				if ( $update )
       
  1033 					unstick_post( $post_ID );
       
  1034 			} elseif ( isset( $post_data['sticky'] ) )  {
       
  1035 				if ( ! current_user_can( $post_type->cap->edit_others_posts ) )
       
  1036 					return new IXR_Error( 401, __( 'Sorry, you are not allowed to stick this post.' ) );
       
  1037 				if ( $post_data['sticky'] )
       
  1038 					stick_post( $post_ID );
       
  1039 				else
       
  1040 					unstick_post( $post_ID );
       
  1041 			}
       
  1042 		}
       
  1043 
       
  1044 		if ( isset( $post_data['post_thumbnail'] ) ) {
       
  1045 			// empty value deletes, non-empty value adds/updates
       
  1046 			if ( ! $post_data['post_thumbnail'] )
       
  1047 				delete_post_thumbnail( $post_ID );
       
  1048 			elseif ( ! set_post_thumbnail( $post_ID, $post_data['post_thumbnail'] ) )
       
  1049 					return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
       
  1050 			unset( $content_struct['post_thumbnail'] );
       
  1051 		}
       
  1052 
       
  1053 		if ( isset( $post_data['custom_fields'] ) )
       
  1054 			$this->set_custom_fields( $post_ID, $post_data['custom_fields'] );
       
  1055 
       
  1056 		if ( isset( $post_data['terms'] ) || isset( $post_data['terms_names'] ) ) {
       
  1057 			$post_type_taxonomies = get_object_taxonomies( $post_data['post_type'], 'objects' );
       
  1058 
       
  1059 			// accumulate term IDs from terms and terms_names
       
  1060 			$terms = array();
       
  1061 
       
  1062 			// first validate the terms specified by ID
       
  1063 			if ( isset( $post_data['terms'] ) && is_array( $post_data['terms'] ) ) {
       
  1064 				$taxonomies = array_keys( $post_data['terms'] );
       
  1065 
       
  1066 				// validating term ids
       
  1067 				foreach ( $taxonomies as $taxonomy ) {
       
  1068 					if ( ! array_key_exists( $taxonomy , $post_type_taxonomies ) )
       
  1069 						return new IXR_Error( 401, __( 'Sorry, one of the given taxonomies is not supported by the post type.' ) );
       
  1070 
       
  1071 					if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->assign_terms ) )
       
  1072 						return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign a term to one of the given taxonomies.' ) );
       
  1073 
       
  1074 					$term_ids = $post_data['terms'][$taxonomy];
       
  1075 					foreach ( $term_ids as $term_id ) {
       
  1076 						$term = get_term_by( 'id', $term_id, $taxonomy );
       
  1077 
       
  1078 						if ( ! $term )
       
  1079 							return new IXR_Error( 403, __( 'Invalid term ID' ) );
       
  1080 
       
  1081 						$terms[$taxonomy][] = (int) $term_id;
       
  1082 					}
       
  1083 				}
       
  1084 			}
       
  1085 
       
  1086 			// now validate terms specified by name
       
  1087 			if ( isset( $post_data['terms_names'] ) && is_array( $post_data['terms_names'] ) ) {
       
  1088 				$taxonomies = array_keys( $post_data['terms_names'] );
       
  1089 
       
  1090 				foreach ( $taxonomies as $taxonomy ) {
       
  1091 					if ( ! array_key_exists( $taxonomy , $post_type_taxonomies ) )
       
  1092 						return new IXR_Error( 401, __( 'Sorry, one of the given taxonomies is not supported by the post type.' ) );
       
  1093 
       
  1094 					if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->assign_terms ) )
       
  1095 						return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign a term to one of the given taxonomies.' ) );
       
  1096 
       
  1097 					// for hierarchical taxonomies, we can't assign a term when multiple terms in the hierarchy share the same name
       
  1098 					$ambiguous_terms = array();
       
  1099 					if ( is_taxonomy_hierarchical( $taxonomy ) ) {
       
  1100 						$tax_term_names = get_terms( $taxonomy, array( 'fields' => 'names', 'hide_empty' => false ) );
       
  1101 
       
  1102 						// count the number of terms with the same name
       
  1103 						$tax_term_names_count = array_count_values( $tax_term_names );
       
  1104 
       
  1105 						// filter out non-ambiguous term names
       
  1106 						$ambiguous_tax_term_counts = array_filter( $tax_term_names_count, array( $this, '_is_greater_than_one') );
       
  1107 
       
  1108 						$ambiguous_terms = array_keys( $ambiguous_tax_term_counts );
       
  1109 					}
       
  1110 
       
  1111 					$term_names = $post_data['terms_names'][$taxonomy];
       
  1112 					foreach ( $term_names as $term_name ) {
       
  1113 						if ( in_array( $term_name, $ambiguous_terms ) )
       
  1114 							return new IXR_Error( 401, __( 'Ambiguous term name used in a hierarchical taxonomy. Please use term ID instead.' ) );
       
  1115 
       
  1116 						$term = get_term_by( 'name', $term_name, $taxonomy );
       
  1117 
       
  1118 						if ( ! $term ) {
       
  1119 							// term doesn't exist, so check that the user is allowed to create new terms
       
  1120 							if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->edit_terms ) )
       
  1121 								return new IXR_Error( 401, __( 'Sorry, you are not allowed to add a term to one of the given taxonomies.' ) );
       
  1122 
       
  1123 							// create the new term
       
  1124 							$term_info = wp_insert_term( $term_name, $taxonomy );
       
  1125 							if ( is_wp_error( $term_info ) )
       
  1126 								return new IXR_Error( 500, $term_info->get_error_message() );
       
  1127 
       
  1128 							$terms[$taxonomy][] = (int) $term_info['term_id'];
       
  1129 						} else {
       
  1130 							$terms[$taxonomy][] = (int) $term->term_id;
       
  1131 						}
       
  1132 					}
       
  1133 				}
       
  1134 			}
       
  1135 
       
  1136 			$post_data['tax_input'] = $terms;
       
  1137 			unset( $post_data['terms'], $post_data['terms_names'] );
       
  1138 		} else {
       
  1139 			// do not allow direct submission of 'tax_input', clients must use 'terms' and/or 'terms_names'
       
  1140 			unset( $post_data['tax_input'], $post_data['post_category'], $post_data['tags_input'] );
       
  1141 		}
       
  1142 
       
  1143 		if ( isset( $post_data['post_format'] ) ) {
       
  1144 			$format = set_post_format( $post_ID, $post_data['post_format'] );
       
  1145 
       
  1146 			if ( is_wp_error( $format ) )
       
  1147 				return new IXR_Error( 500, $format->get_error_message() );
       
  1148 
       
  1149 			unset( $post_data['post_format'] );
       
  1150 		}
       
  1151 
       
  1152 		// Handle enclosures
       
  1153 		$enclosure = isset( $post_data['enclosure'] ) ? $post_data['enclosure'] : null;
       
  1154 		$this->add_enclosure_if_new( $post_ID, $enclosure );
       
  1155 
       
  1156 		$this->attach_uploads( $post_ID, $post_data['post_content'] );
       
  1157 
       
  1158 		$post_data = apply_filters( 'xmlrpc_wp_insert_post_data', $post_data, $content_struct );
       
  1159 
       
  1160 		$post_ID = wp_insert_post( $post_data, true );
       
  1161 		if ( is_wp_error( $post_ID ) )
       
  1162 			return new IXR_Error( 500, $post_ID->get_error_message() );
       
  1163 
       
  1164 		if ( ! $post_ID )
       
  1165 			return new IXR_Error( 401, __( 'Sorry, your entry could not be posted. Something wrong happened.' ) );
       
  1166 
       
  1167 		return strval( $post_ID );
       
  1168 	}
       
  1169 
       
  1170 	/**
       
  1171 	 * Edit a post for any registered post type.
       
  1172 	 *
       
  1173 	 * The $content_struct parameter only needs to contain fields that
       
  1174 	 * should be changed. All other fields will retain their existing values.
       
  1175 	 *
       
  1176 	 * @since 3.4.0
       
  1177 	 *
       
  1178 	 * @param array $args Method parameters. Contains:
       
  1179 	 *  - int     $blog_id
       
  1180 	 *  - string  $username
       
  1181 	 *  - string  $password
       
  1182 	 *  - int     $post_id
       
  1183 	 *  - array   $content_struct
       
  1184 	 * @return true on success
       
  1185 	 */
       
  1186 	function wp_editPost( $args ) {
       
  1187 		if ( ! $this->minimum_args( $args, 5 ) )
       
  1188 			return $this->error;
       
  1189 
       
  1190 		$this->escape( $args );
       
  1191 
       
  1192 		$blog_id        = (int) $args[0];
       
  1193 		$username       = $args[1];
       
  1194 		$password       = $args[2];
       
  1195 		$post_id        = (int) $args[3];
       
  1196 		$content_struct = $args[4];
       
  1197 
       
  1198 		if ( ! $user = $this->login( $username, $password ) )
       
  1199 			return $this->error;
       
  1200 
       
  1201 		do_action( 'xmlrpc_call', 'wp.editPost' );
       
  1202 
       
  1203 		$post = get_post( $post_id, ARRAY_A );
       
  1204 
       
  1205 		if ( empty( $post['ID'] ) )
       
  1206 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  1207 
       
  1208 		// convert the date field back to IXR form
       
  1209 		$post['post_date'] = $this->_convert_date( $post['post_date'] );
       
  1210 
       
  1211 		// ignore the existing GMT date if it is empty or a non-GMT date was supplied in $content_struct,
       
  1212 		// since _insert_post will ignore the non-GMT date if the GMT date is set
       
  1213 		if ( $post['post_date_gmt'] == '0000-00-00 00:00:00' || isset( $content_struct['post_date'] ) )
       
  1214 			unset( $post['post_date_gmt'] );
       
  1215 		else
       
  1216 			$post['post_date_gmt'] = $this->_convert_date( $post['post_date_gmt'] );
       
  1217 
       
  1218 		$this->escape( $post );
       
  1219 		$merged_content_struct = array_merge( $post, $content_struct );
       
  1220 
       
  1221 		$retval = $this->_insert_post( $user, $merged_content_struct );
       
  1222 		if ( $retval instanceof IXR_Error )
       
  1223 			return $retval;
       
  1224 
       
  1225 		return true;
       
  1226 	}
       
  1227 
       
  1228 	/**
       
  1229 	 * Delete a post for any registered post type.
       
  1230 	 *
       
  1231 	 * @since 3.4.0
       
  1232 	 *
       
  1233 	 * @uses wp_delete_post()
       
  1234 	 * @param array $args Method parameters. Contains:
       
  1235 	 *  - int     $blog_id
       
  1236 	 *  - string  $username
       
  1237 	 *  - string  $password
       
  1238 	 *  - int     $post_id
       
  1239 	 * @return true on success
       
  1240 	 */
       
  1241 	function wp_deletePost( $args ) {
       
  1242 		if ( ! $this->minimum_args( $args, 4 ) )
       
  1243 			return $this->error;
       
  1244 
       
  1245 		$this->escape( $args );
       
  1246 
       
  1247 		$blog_id    = (int) $args[0];
       
  1248 		$username   = $args[1];
       
  1249 		$password   = $args[2];
       
  1250 		$post_id    = (int) $args[3];
       
  1251 
       
  1252 		if ( ! $user = $this->login( $username, $password ) )
       
  1253 			return $this->error;
       
  1254 
       
  1255 		do_action( 'xmlrpc_call', 'wp.deletePost' );
       
  1256 
       
  1257 		$post = wp_get_single_post( $post_id, ARRAY_A );
       
  1258 		if ( empty( $post['ID'] ) )
       
  1259 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  1260 
       
  1261 		$post_type = get_post_type_object( $post['post_type'] );
       
  1262 		if ( ! current_user_can( $post_type->cap->delete_post, $post_id ) )
       
  1263 			return new IXR_Error( 401, __( 'Sorry, you are not allowed to delete this post.' ) );
       
  1264 
       
  1265 		$result = wp_delete_post( $post_id );
       
  1266 
       
  1267 		if ( ! $result )
       
  1268 			return new IXR_Error( 500, __( 'The post cannot be deleted.' ) );
       
  1269 
       
  1270 		return true;
       
  1271 	}
       
  1272 
       
  1273 	/**
       
  1274 	 * Retrieve a post.
       
  1275 	 *
       
  1276 	 * @since 3.4.0
       
  1277 	 *
       
  1278 	 * The optional $fields parameter specifies what fields will be included
       
  1279 	 * in the response array. This should be a list of field names. 'post_id' will
       
  1280 	 * always be included in the response regardless of the value of $fields.
       
  1281 	 *
       
  1282 	 * Instead of, or in addition to, individual field names, conceptual group
       
  1283 	 * names can be used to specify multiple fields. The available conceptual
       
  1284 	 * groups are 'post' (all basic fields), 'taxonomies', 'custom_fields',
       
  1285 	 * and 'enclosure'.
       
  1286 	 *
       
  1287 	 * @uses wp_get_single_post()
       
  1288 	 * @param array $args Method parameters. Contains:
       
  1289 	 *  - int     $post_id
       
  1290 	 *  - string  $username
       
  1291 	 *  - string  $password
       
  1292 	 *  - array   $fields optional
       
  1293 	 * @return array contains (based on $fields parameter):
       
  1294 	 *  - 'post_id'
       
  1295 	 *  - 'post_title'
       
  1296 	 *  - 'post_date'
       
  1297 	 *  - 'post_date_gmt'
       
  1298 	 *  - 'post_modified'
       
  1299 	 *  - 'post_modified_gmt'
       
  1300 	 *  - 'post_status'
       
  1301 	 *  - 'post_type'
       
  1302 	 *  - 'post_name'
       
  1303 	 *  - 'post_author'
       
  1304 	 *  - 'post_password'
       
  1305 	 *  - 'post_excerpt'
       
  1306 	 *  - 'post_content'
       
  1307 	 *  - 'link'
       
  1308 	 *  - 'comment_status'
       
  1309 	 *  - 'ping_status'
       
  1310 	 *  - 'sticky'
       
  1311 	 *  - 'custom_fields'
       
  1312 	 *  - 'terms'
       
  1313 	 *  - 'categories'
       
  1314 	 *  - 'tags'
       
  1315 	 *  - 'enclosure'
       
  1316 	 */
       
  1317 	function wp_getPost( $args ) {
       
  1318 		if ( ! $this->minimum_args( $args, 4 ) )
       
  1319 			return $this->error;
       
  1320 
       
  1321 		$this->escape( $args );
       
  1322 
       
  1323 		$blog_id            = (int) $args[0];
       
  1324 		$username           = $args[1];
       
  1325 		$password           = $args[2];
       
  1326 		$post_id            = (int) $args[3];
       
  1327 
       
  1328 		if ( isset( $args[4] ) )
       
  1329 			$fields = $args[4];
       
  1330 		else
       
  1331 			$fields = apply_filters( 'xmlrpc_default_post_fields', array( 'post', 'terms', 'custom_fields' ), 'wp.getPost' );
       
  1332 
       
  1333 		if ( ! $user = $this->login( $username, $password ) )
       
  1334 			return $this->error;
       
  1335 
       
  1336 		do_action( 'xmlrpc_call', 'wp.getPost' );
       
  1337 
       
  1338 		$post = wp_get_single_post( $post_id, ARRAY_A );
       
  1339 
       
  1340 		if ( empty( $post['ID'] ) )
       
  1341 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  1342 
       
  1343 		$post_type = get_post_type_object( $post['post_type'] );
       
  1344 		if ( ! current_user_can( $post_type->cap->edit_post, $post_id ) )
       
  1345 			return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
       
  1346 
       
  1347 		return $this->_prepare_post( $post, $fields );
       
  1348 	}
       
  1349 
       
  1350 	/**
       
  1351 	 * Retrieve posts.
       
  1352 	 *
       
  1353 	 * @since 3.4.0
       
  1354 	 *
       
  1355 	 * The optional $filter parameter modifies the query used to retrieve posts.
       
  1356 	 * Accepted keys are 'post_type', 'post_status', 'number', 'offset',
       
  1357 	 * 'orderby', and 'order'.
       
  1358 	 *
       
  1359 	 * The optional $fields parameter specifies what fields will be included
       
  1360 	 * in the response array.
       
  1361 	 *
       
  1362 	 * @uses wp_get_recent_posts()
       
  1363 	 * @see wp_getPost() for more on $fields
       
  1364 	 * @see get_posts() for more on $filter values
       
  1365 	 *
       
  1366 	 * @param array $args Method parameters. Contains:
       
  1367 	 *  - int     $blog_id
       
  1368 	 *  - string  $username
       
  1369 	 *  - string  $password
       
  1370 	 *  - array   $filter optional
       
  1371 	 *  - array   $fields optional
       
  1372 	 * @return array contains a collection of posts.
       
  1373 	 */
       
  1374 	function wp_getPosts( $args ) {
       
  1375 		if ( ! $this->minimum_args( $args, 3 ) )
       
  1376 			return $this->error;
       
  1377 
       
  1378 		$this->escape( $args );
       
  1379 
       
  1380 		$blog_id    = (int) $args[0];
       
  1381 		$username   = $args[1];
       
  1382 		$password   = $args[2];
       
  1383 		$filter     = isset( $args[3] ) ? $args[3] : array();
       
  1384 
       
  1385 		if ( isset( $args[4] ) )
       
  1386 			$fields = $args[4];
       
  1387 		else
       
  1388 			$fields = apply_filters( 'xmlrpc_default_post_fields', array( 'post', 'terms', 'custom_fields' ), 'wp.getPosts' );
       
  1389 
       
  1390 		if ( ! $user = $this->login( $username, $password ) )
       
  1391 			return $this->error;
       
  1392 
       
  1393 		do_action( 'xmlrpc_call', 'wp.getPosts' );
       
  1394 
       
  1395 		$query = array();
       
  1396 
       
  1397 		if ( isset( $filter['post_type'] ) ) {
       
  1398 			$post_type = get_post_type_object( $filter['post_type'] );
       
  1399 			if ( ! ( (bool) $post_type ) )
       
  1400 				return new IXR_Error( 403, __( 'The post type specified is not valid' ) );
       
  1401 		} else {
       
  1402 			$post_type = get_post_type_object( 'post' );
       
  1403 		}
       
  1404 
       
  1405 		if ( ! current_user_can( $post_type->cap->edit_posts ) )
       
  1406 			return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit posts in this post type' ));
       
  1407 
       
  1408 		$query['post_type'] = $post_type->name;
       
  1409 
       
  1410 		if ( isset( $filter['post_status'] ) )
       
  1411 			$query['post_status'] = $filter['post_status'];
       
  1412 
       
  1413 		if ( isset( $filter['number'] ) )
       
  1414 			$query['numberposts'] = absint( $filter['number'] );
       
  1415 
       
  1416 		if ( isset( $filter['offset'] ) )
       
  1417 			$query['offset'] = absint( $filter['offset'] );
       
  1418 
       
  1419 		if ( isset( $filter['orderby'] ) ) {
       
  1420 			$query['orderby'] = $filter['orderby'];
       
  1421 
       
  1422 			if ( isset( $filter['order'] ) )
       
  1423 				$query['order'] = $filter['order'];
       
  1424 		}
       
  1425 
       
  1426 		$posts_list = wp_get_recent_posts( $query );
       
  1427 
       
  1428 		if ( ! $posts_list )
       
  1429 			return array();
       
  1430 
       
  1431 		// holds all the posts data
       
  1432 		$struct = array();
       
  1433 
       
  1434 		foreach ( $posts_list as $post ) {
       
  1435 			$post_type = get_post_type_object( $post['post_type'] );
       
  1436 			if ( ! current_user_can( $post_type->cap->edit_post, $post['ID'] ) )
       
  1437 				continue;
       
  1438 
       
  1439 			$struct[] = $this->_prepare_post( $post, $fields );
       
  1440 		}
       
  1441 
       
  1442 		return $struct;
       
  1443 	}
       
  1444 
       
  1445 	/**
       
  1446 	 * Create a new term.
       
  1447 	 *
       
  1448 	 * @since 3.4.0
       
  1449 	 *
       
  1450 	 * @uses wp_insert_term()
       
  1451 	 * @param array $args Method parameters. Contains:
       
  1452 	 *  - int     $blog_id
       
  1453 	 *  - string  $username
       
  1454 	 *  - string  $password
       
  1455 	 *  - array   $content_struct
       
  1456 	 *      The $content_struct must contain:
       
  1457 	 *      - 'name'
       
  1458 	 *      - 'taxonomy'
       
  1459 	 *      Also, it can optionally contain:
       
  1460 	 *      - 'parent'
       
  1461 	 *      - 'description'
       
  1462 	 *      - 'slug'
       
  1463 	 * @return string term_id
       
  1464 	 */
       
  1465 	function wp_newTerm( $args ) {
       
  1466 		if ( ! $this->minimum_args( $args, 4 ) )
       
  1467 			return $this->error;
       
  1468 
       
  1469 		$this->escape( $args );
       
  1470 
       
  1471 		$blog_id            = (int) $args[0];
       
  1472 		$username           = $args[1];
       
  1473 		$password           = $args[2];
       
  1474 		$content_struct     = $args[3];
       
  1475 
       
  1476 		if ( ! $user = $this->login( $username, $password ) )
       
  1477 			return $this->error;
       
  1478 
       
  1479 		do_action( 'xmlrpc_call', 'wp.newTerm' );
       
  1480 
       
  1481 		if ( ! taxonomy_exists( $content_struct['taxonomy'] ) )
       
  1482 			return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
       
  1483 
       
  1484 		$taxonomy = get_taxonomy( $content_struct['taxonomy'] );
       
  1485 
       
  1486 		if ( ! current_user_can( $taxonomy->cap->manage_terms ) )
       
  1487 			return new IXR_Error( 401, __( 'You are not allowed to create terms in this taxonomy.' ) );
       
  1488 
       
  1489 		$taxonomy = (array) $taxonomy;
       
  1490 
       
  1491 		// hold the data of the term
       
  1492 		$term_data = array();
       
  1493 
       
  1494 		$term_data['name'] = trim( $content_struct['name'] );
       
  1495 		if ( empty( $term_data['name'] ) )
       
  1496 			return new IXR_Error( 403, __( 'The term name cannot be empty.' ) );
       
  1497 
       
  1498 		if ( isset( $content_struct['parent'] ) ) {
       
  1499 			if ( ! $taxonomy['hierarchical'] )
       
  1500 				return new IXR_Error( 403, __( 'This taxonomy is not hierarchical.' ) );
       
  1501 
       
  1502 			$parent_term_id = (int) $content_struct['parent'];
       
  1503 			$parent_term = get_term( $parent_term_id , $taxonomy['name'] );
       
  1504 
       
  1505 			if ( is_wp_error( $parent_term ) )
       
  1506 				return new IXR_Error( 500, $parent_term->get_error_message() );
       
  1507 
       
  1508 			if ( ! $parent_term )
       
  1509 				return new IXR_Error( 403, __( 'Parent term does not exist.' ) );
       
  1510 
       
  1511 			$term_data['parent'] = $content_struct['parent'];
       
  1512 		}
       
  1513 
       
  1514 		if ( isset( $content_struct['description'] ) )
       
  1515 			$term_data['description'] = $content_struct['description'];
       
  1516 
       
  1517 		if ( isset( $content_struct['slug'] ) )
       
  1518 			$term_data['slug'] = $content_struct['slug'];
       
  1519 
       
  1520 		$term = wp_insert_term( $term_data['name'] , $taxonomy['name'] , $term_data );
       
  1521 
       
  1522 		if ( is_wp_error( $term ) )
       
  1523 			return new IXR_Error( 500, $term->get_error_message() );
       
  1524 
       
  1525 		if ( ! $term )
       
  1526 			return new IXR_Error( 500, __( 'Sorry, your term could not be created. Something wrong happened.' ) );
       
  1527 
       
  1528 		return strval( $term['term_id'] );
       
  1529 	}
       
  1530 
       
  1531 	/**
       
  1532 	 * Edit a term.
       
  1533 	 *
       
  1534 	 * @since 3.4.0
       
  1535 	 *
       
  1536 	 * @uses wp_update_term()
       
  1537 	 * @param array $args Method parameters. Contains:
       
  1538 	 *  - int     $blog_id
       
  1539 	 *  - string  $username
       
  1540 	 *  - string  $password
       
  1541 	 *  - string  $term_id
       
  1542 	 *  - array   $content_struct
       
  1543 	 *      The $content_struct must contain:
       
  1544 	 *      - 'taxonomy'
       
  1545 	 *      Also, it can optionally contain:
       
  1546 	 *      - 'name'
       
  1547 	 *      - 'parent'
       
  1548 	 *      - 'description'
       
  1549 	 *      - 'slug'
       
  1550 	 * @return bool True, on success.
       
  1551 	 */
       
  1552 	function wp_editTerm( $args ) {
       
  1553 		if ( ! $this->minimum_args( $args, 5 ) )
       
  1554 			return $this->error;
       
  1555 
       
  1556 		$this->escape( $args );
       
  1557 
       
  1558 		$blog_id            = (int) $args[0];
       
  1559 		$username           = $args[1];
       
  1560 		$password           = $args[2];
       
  1561 		$term_id            = (int) $args[3];
       
  1562 		$content_struct     = $args[4];
       
  1563 
       
  1564 		if ( ! $user = $this->login( $username, $password ) )
       
  1565 			return $this->error;
       
  1566 
       
  1567 		do_action( 'xmlrpc_call', 'wp.editTerm' );
       
  1568 
       
  1569 		if ( ! taxonomy_exists( $content_struct['taxonomy'] ) )
       
  1570 			return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
       
  1571 
       
  1572 		$taxonomy = get_taxonomy( $content_struct['taxonomy'] );
       
  1573 
       
  1574 		if ( ! current_user_can( $taxonomy->cap->edit_terms ) )
       
  1575 			return new IXR_Error( 401, __( 'You are not allowed to edit terms in this taxonomy.' ) );
       
  1576 
       
  1577 		$taxonomy = (array) $taxonomy;
       
  1578 
       
  1579 		// hold the data of the term
       
  1580 		$term_data = array();
       
  1581 
       
  1582 		$term = get_term( $term_id , $content_struct['taxonomy'] );
       
  1583 
       
  1584 		if ( is_wp_error( $term ) )
       
  1585 			return new IXR_Error( 500, $term->get_error_message() );
       
  1586 
       
  1587 		if ( ! $term )
       
  1588 			return new IXR_Error( 404, __( 'Invalid term ID' ) );
       
  1589 
       
  1590 		if ( isset( $content_struct['name'] ) ) {
       
  1591 			$term_data['name'] = trim( $content_struct['name'] );
       
  1592 
       
  1593 			if ( empty( $term_data['name'] ) )
       
  1594 				return new IXR_Error( 403, __( 'The term name cannot be empty.' ) );
       
  1595 		}
       
  1596 
       
  1597 		if ( isset( $content_struct['parent'] ) ) {
       
  1598 			if ( ! $taxonomy['hierarchical'] )
       
  1599 				return new IXR_Error( 403, __( "This taxonomy is not hierarchical so you can't set a parent." ) );
       
  1600 
       
  1601 			$parent_term_id = (int) $content_struct['parent'];
       
  1602 			$parent_term = get_term( $parent_term_id , $taxonomy['name'] );
       
  1603 
       
  1604 			if ( is_wp_error( $parent_term ) )
       
  1605 				return new IXR_Error( 500, $parent_term->get_error_message() );
       
  1606 
       
  1607 			if ( ! $parent_term )
       
  1608 				return new IXR_Error( 403, __( 'Parent term does not exist.' ) );
       
  1609 
       
  1610 			$term_data['parent'] = $content_struct['parent'];
       
  1611 		}
       
  1612 
       
  1613 		if ( isset( $content_struct['description'] ) )
       
  1614 			$term_data['description'] = $content_struct['description'];
       
  1615 
       
  1616 		if ( isset( $content_struct['slug'] ) )
       
  1617 			$term_data['slug'] = $content_struct['slug'];
       
  1618 
       
  1619 		$term = wp_update_term( $term_id , $taxonomy['name'] , $term_data );
       
  1620 
       
  1621 		if ( is_wp_error( $term ) )
       
  1622 			return new IXR_Error( 500, $term->get_error_message() );
       
  1623 
       
  1624 		if ( ! $term )
       
  1625 			return new IXR_Error( 500, __( 'Sorry, editing the term failed.' ) );
       
  1626 
       
  1627 		return true;
       
  1628 	}
       
  1629 
       
  1630 	/**
       
  1631 	 * Delete a term.
       
  1632 	 *
       
  1633 	 * @since 3.4.0
       
  1634 	 *
       
  1635 	 * @uses wp_delete_term()
       
  1636 	 * @param array $args Method parameters. Contains:
       
  1637 	 *  - int     $blog_id
       
  1638 	 *  - string  $username
       
  1639 	 *  - string  $password
       
  1640 	 *  - string  $taxnomy_name
       
  1641 	 *  - string     $term_id
       
  1642 	 * @return boolean|IXR_Error If it suceeded true else a reason why not
       
  1643 	 */
       
  1644 	function wp_deleteTerm( $args ) {
       
  1645 		if ( ! $this->minimum_args( $args, 5 ) )
       
  1646 			return $this->error;
       
  1647 
       
  1648 		$this->escape( $args );
       
  1649 
       
  1650 		$blog_id            = (int) $args[0];
       
  1651 		$username           = $args[1];
       
  1652 		$password           = $args[2];
       
  1653 		$taxonomy           = $args[3];
       
  1654 		$term_id            = (int) $args[4];
       
  1655 
       
  1656 		if ( ! $user = $this->login( $username, $password ) )
       
  1657 			return $this->error;
       
  1658 
       
  1659 		do_action( 'xmlrpc_call', 'wp.deleteTerm' );
       
  1660 
       
  1661 		if ( ! taxonomy_exists( $taxonomy ) )
       
  1662 			return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
       
  1663 
       
  1664 		$taxonomy = get_taxonomy( $taxonomy );
       
  1665 
       
  1666 		if ( ! current_user_can( $taxonomy->cap->delete_terms ) )
       
  1667 			return new IXR_Error( 401, __( 'You are not allowed to delete terms in this taxonomy.' ) );
       
  1668 
       
  1669 		$term = get_term( $term_id, $taxonomy->name );
       
  1670 
       
  1671 		if ( is_wp_error( $term ) )
       
  1672 			return new IXR_Error( 500, $term->get_error_message() );
       
  1673 
       
  1674 		if ( ! $term )
       
  1675 			return new IXR_Error( 404, __( 'Invalid term ID' ) );
       
  1676 
       
  1677 		$result = wp_delete_term( $term_id, $taxonomy->name );
       
  1678 
       
  1679 		if ( is_wp_error( $result ) )
       
  1680 			return new IXR_Error( 500, $term->get_error_message() );
       
  1681 
       
  1682 		if ( ! $result )
       
  1683 			return new IXR_Error( 500, __( 'Sorry, deleting the term failed.' ) );
       
  1684 
       
  1685 		return $result;
       
  1686 	}
       
  1687 
       
  1688 	/**
       
  1689 	 * Retrieve a term.
       
  1690 	 *
       
  1691 	 * @since 3.4.0
       
  1692 	 *
       
  1693 	 * @uses get_term()
       
  1694 	 * @param array $args Method parameters. Contains:
       
  1695 	 *  - int     $blog_id
       
  1696 	 *  - string  $username
       
  1697 	 *  - string  $password
       
  1698 	 *  - string  $taxonomy
       
  1699 	 *  - string  $term_id
       
  1700 	 * @return array contains:
       
  1701 	 *  - 'term_id'
       
  1702 	 *  - 'name'
       
  1703 	 *  - 'slug'
       
  1704 	 *  - 'term_group'
       
  1705 	 *  - 'term_taxonomy_id'
       
  1706 	 *  - 'taxonomy'
       
  1707 	 *  - 'description'
       
  1708 	 *  - 'parent'
       
  1709 	 *  - 'count'
       
  1710 	 */
       
  1711 	function wp_getTerm( $args ) {
       
  1712 		if ( ! $this->minimum_args( $args, 5 ) )
       
  1713 			return $this->error;
       
  1714 
       
  1715 		$this->escape( $args );
       
  1716 
       
  1717 		$blog_id            = (int) $args[0];
       
  1718 		$username           = $args[1];
       
  1719 		$password           = $args[2];
       
  1720 		$taxonomy           = $args[3];
       
  1721 		$term_id            = (int) $args[4];
       
  1722 
       
  1723 		if ( ! $user = $this->login( $username, $password ) )
       
  1724 			return $this->error;
       
  1725 
       
  1726 		do_action( 'xmlrpc_call', 'wp.getTerm' );
       
  1727 
       
  1728 		if ( ! taxonomy_exists( $taxonomy ) )
       
  1729 			return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
       
  1730 
       
  1731 		$taxonomy = get_taxonomy( $taxonomy );
       
  1732 
       
  1733 		if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
       
  1734 			return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) );
       
  1735 
       
  1736 		$term = get_term( $term_id , $taxonomy->name, ARRAY_A );
       
  1737 
       
  1738 		if ( is_wp_error( $term ) )
       
  1739 			return new IXR_Error( 500, $term->get_error_message() );
       
  1740 
       
  1741 		if ( ! $term )
       
  1742 			return new IXR_Error( 404, __( 'Invalid term ID' ) );
       
  1743 
       
  1744 		return $this->_prepare_term( $term );
       
  1745 	}
       
  1746 
       
  1747 	/**
       
  1748 	 * Retrieve all terms for a taxonomy.
       
  1749 	 *
       
  1750 	 * @since 3.4.0
       
  1751 	 *
       
  1752 	 * The optional $filter parameter modifies the query used to retrieve terms.
       
  1753 	 * Accepted keys are 'number', 'offset', 'orderby', 'order', 'hide_empty', and 'search'.
       
  1754 	 *
       
  1755 	 * @uses get_terms()
       
  1756 	 * @param array $args Method parameters. Contains:
       
  1757 	 *  - int     $blog_id
       
  1758 	 *  - string  $username
       
  1759 	 *  - string  $password
       
  1760 	 *  - string  $taxonomy
       
  1761 	 *  - array   $filter optional
       
  1762 	 * @return array terms
       
  1763 	 */
       
  1764 	function wp_getTerms( $args ) {
       
  1765 		if ( ! $this->minimum_args( $args, 4 ) )
       
  1766 			return $this->error;
       
  1767 
       
  1768 		$this->escape( $args );
       
  1769 
       
  1770 		$blog_id        = (int) $args[0];
       
  1771 		$username       = $args[1];
       
  1772 		$password       = $args[2];
       
  1773 		$taxonomy       = $args[3];
       
  1774 		$filter         = isset( $args[4] ) ? $args[4] : array();
       
  1775 
       
  1776 		if ( ! $user = $this->login( $username, $password ) )
       
  1777 			return $this->error;
       
  1778 
       
  1779 		do_action( 'xmlrpc_call', 'wp.getTerms' );
       
  1780 
       
  1781 		if ( ! taxonomy_exists( $taxonomy ) )
       
  1782 			return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
       
  1783 
       
  1784 		$taxonomy = get_taxonomy( $taxonomy );
       
  1785 
       
  1786 		if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
       
  1787 			return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) );
       
  1788 
       
  1789 		$query = array();
       
  1790 
       
  1791 		if ( isset( $filter['number'] ) )
       
  1792 			$query['number'] = absint( $filter['number'] );
       
  1793 
       
  1794 		if ( isset( $filter['offset'] ) )
       
  1795 			$query['offset'] = absint( $filter['offset'] );
       
  1796 
       
  1797 		if ( isset( $filter['orderby'] ) ) {
       
  1798 			$query['orderby'] = $filter['orderby'];
       
  1799 
       
  1800 			if ( isset( $filter['order'] ) )
       
  1801 				$query['order'] = $filter['order'];
       
  1802 		}
       
  1803 
       
  1804 		if ( isset( $filter['hide_empty'] ) )
       
  1805 			$query['hide_empty'] = $filter['hide_empty'];
       
  1806 		else
       
  1807 			$query['get'] = 'all';
       
  1808 
       
  1809 		if ( isset( $filter['search'] ) )
       
  1810 			$query['search'] = $filter['search'];
       
  1811 
       
  1812 		$terms = get_terms( $taxonomy->name, $query );
       
  1813 
       
  1814 		if ( is_wp_error( $terms ) )
       
  1815 			return new IXR_Error( 500, $terms->get_error_message() );
       
  1816 
       
  1817 		$struct = array();
       
  1818 
       
  1819 		foreach ( $terms as $term ) {
       
  1820 			$struct[] = $this->_prepare_term( $term );
       
  1821 		}
       
  1822 
       
  1823 		return $struct;
       
  1824 	}
       
  1825 
       
  1826 	/**
       
  1827 	 * Retrieve a taxonomy.
       
  1828 	 *
       
  1829 	 * @since 3.4.0
       
  1830 	 *
       
  1831 	 * @uses get_taxonomy()
       
  1832 	 * @param array $args Method parameters. Contains:
       
  1833 	 *  - int     $blog_id
       
  1834 	 *  - string  $username
       
  1835 	 *  - string  $password
       
  1836 	 *  - string  $taxonomy
       
  1837 	 * @return array (@see get_taxonomy())
       
  1838 	 */
       
  1839 	function wp_getTaxonomy( $args ) {
       
  1840 		if ( ! $this->minimum_args( $args, 4 ) )
       
  1841 			return $this->error;
       
  1842 
       
  1843 		$this->escape( $args );
       
  1844 
       
  1845 		$blog_id        = (int) $args[0];
       
  1846 		$username       = $args[1];
       
  1847 		$password       = $args[2];
       
  1848 		$taxonomy       = $args[3];
       
  1849 
       
  1850 		if ( isset( $args[4] ) )
       
  1851 			$fields = $args[4];
       
  1852 		else
       
  1853 			$fields = apply_filters( 'xmlrpc_default_taxonomy_fields', array( 'labels', 'cap', 'object_type' ), 'wp.getTaxonomy' );
       
  1854 
       
  1855 		if ( ! $user = $this->login( $username, $password ) )
       
  1856 			return $this->error;
       
  1857 
       
  1858 		do_action( 'xmlrpc_call', 'wp.getTaxonomy' );
       
  1859 
       
  1860 		if ( ! taxonomy_exists( $taxonomy ) )
       
  1861 			return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
       
  1862 
       
  1863 		$taxonomy = get_taxonomy( $taxonomy );
       
  1864 
       
  1865 		if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
       
  1866 			return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) );
       
  1867 
       
  1868 		return $this->_prepare_taxonomy( $taxonomy, $fields );
       
  1869 	}
       
  1870 
       
  1871 	/**
       
  1872 	 * Retrieve all taxonomies.
       
  1873 	 *
       
  1874 	 * @since 3.4.0
       
  1875 	 *
       
  1876 	 * @uses get_taxonomies()
       
  1877 	 * @param array $args Method parameters. Contains:
       
  1878 	 *  - int     $blog_id
       
  1879 	 *  - string  $username
       
  1880 	 *  - string  $password
       
  1881 	 * @return array taxonomies
       
  1882 	 */
       
  1883 	function wp_getTaxonomies( $args ) {
       
  1884 		if ( ! $this->minimum_args( $args, 3 ) )
       
  1885 			return $this->error;
       
  1886 
       
  1887 		$this->escape( $args );
       
  1888 
       
  1889 		$blog_id            = (int) $args[0];
       
  1890 		$username           = $args[1];
       
  1891 		$password           = $args[2];
       
  1892 		$filter             = isset( $args[3] ) ? $args[3] : array( 'public' => true );
       
  1893 
       
  1894 		if ( isset( $args[4] ) )
       
  1895 			$fields = $args[4];
       
  1896 		else
       
  1897 			$fields = apply_filters( 'xmlrpc_default_taxonomy_fields', array( 'labels', 'cap', 'object_type' ), 'wp.getTaxonomies' );
       
  1898 
       
  1899 		if ( ! $user = $this->login( $username, $password ) )
       
  1900 			return $this->error;
       
  1901 
       
  1902 		do_action( 'xmlrpc_call', 'wp.getTaxonomies' );
       
  1903 
       
  1904 		$taxonomies = get_taxonomies( $filter, 'objects' );
       
  1905 
       
  1906 		// holds all the taxonomy data
       
  1907 		$struct = array();
       
  1908 
       
  1909 		foreach ( $taxonomies as $taxonomy ) {
       
  1910 			// capability check for post_types
       
  1911 			if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
       
  1912 				continue;
       
  1913 
       
  1914 			$struct[] = $this->_prepare_taxonomy( $taxonomy, $fields );
       
  1915 		}
       
  1916 
       
  1917 		return $struct;
       
  1918 	}
       
  1919 
       
  1920 	/**
       
  1921 	 * Retrieve page.
       
  1922 	 *
       
  1923 	 * @since 2.2.0
       
  1924 	 *
       
  1925 	 * @param array $args Method parameters. Contains:
       
  1926 	 *  - blog_id
       
  1927 	 *  - page_id
       
  1928 	 *  - username
       
  1929 	 *  - password
       
  1930 	 * @return array
       
  1931 	 */
       
  1932 	function wp_getPage($args) {
       
  1933 		$this->escape($args);
       
  1934 
       
  1935 		$blog_id	= (int) $args[0];
       
  1936 		$page_id	= (int) $args[1];
       
  1937 		$username	= $args[2];
       
  1938 		$password	= $args[3];
       
  1939 
       
  1940 		if ( !$user = $this->login($username, $password) ) {
       
  1941 			return $this->error;
       
  1942 		}
       
  1943 
       
  1944 		$page = get_page($page_id);
       
  1945 		if ( ! $page )
       
  1946 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  1947 
       
  1948 		if ( !current_user_can( 'edit_page', $page_id ) )
       
  1949 			return new IXR_Error( 401, __( 'Sorry, you cannot edit this page.' ) );
       
  1950 
       
  1951 		do_action('xmlrpc_call', 'wp.getPage');
       
  1952 
       
  1953 		// If we found the page then format the data.
       
  1954 		if ( $page->ID && ($page->post_type == 'page') ) {
       
  1955 			return $this->_prepare_page( $page );
       
  1956 		}
       
  1957 		// If the page doesn't exist indicate that.
       
  1958 		else {
       
  1959 			return(new IXR_Error(404, __('Sorry, no such page.')));
       
  1960 		}
       
  1961 	}
       
  1962 
       
  1963 	/**
       
  1964 	 * Retrieve Pages.
       
  1965 	 *
       
  1966 	 * @since 2.2.0
       
  1967 	 *
       
  1968 	 * @param array $args Method parameters. Contains:
       
  1969 	 *  - blog_id
       
  1970 	 *  - username
       
  1971 	 *  - password
       
  1972 	 *  - num_pages
       
  1973 	 * @return array
       
  1974 	 */
       
  1975 	function wp_getPages($args) {
       
  1976 		$this->escape($args);
       
  1977 
       
  1978 		$blog_id	= (int) $args[0];
       
  1979 		$username	= $args[1];
       
  1980 		$password	= $args[2];
       
  1981 		$num_pages	= isset($args[3]) ? (int) $args[3] : 10;
       
  1982 
       
  1983 		if ( !$user = $this->login($username, $password) )
       
  1984 			return $this->error;
       
  1985 
       
  1986 		if ( !current_user_can( 'edit_pages' ) )
       
  1987 			return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) );
       
  1988 
       
  1989 		do_action('xmlrpc_call', 'wp.getPages');
       
  1990 
       
  1991 		$pages = get_posts( array('post_type' => 'page', 'post_status' => 'any', 'numberposts' => $num_pages) );
       
  1992 		$num_pages = count($pages);
       
  1993 
       
  1994 		// If we have pages, put together their info.
       
  1995 		if ( $num_pages >= 1 ) {
       
  1996 			$pages_struct = array();
       
  1997 
       
  1998 			foreach ($pages as $page) {
       
  1999 				if ( current_user_can( 'edit_page', $page->ID ) )
       
  2000 					$pages_struct[] = $this->_prepare_page( $page );
       
  2001 			}
       
  2002 
       
  2003 			return($pages_struct);
       
  2004 		}
       
  2005 		// If no pages were found return an error.
       
  2006 		else {
       
  2007 			return(array());
       
  2008 		}
       
  2009 	}
       
  2010 
       
  2011 	/**
       
  2012 	 * Create new page.
       
  2013 	 *
       
  2014 	 * @since 2.2.0
       
  2015 	 *
       
  2016 	 * @param array $args Method parameters. See {@link wp_xmlrpc_server::mw_newPost()}
       
  2017 	 * @return unknown
       
  2018 	 */
       
  2019 	function wp_newPage($args) {
       
  2020 		// Items not escaped here will be escaped in newPost.
       
  2021 		$username	= $this->escape($args[1]);
       
  2022 		$password	= $this->escape($args[2]);
       
  2023 		$page		= $args[3];
       
  2024 		$publish	= $args[4];
       
  2025 
       
  2026 		if ( !$user = $this->login($username, $password) )
       
  2027 			return $this->error;
       
  2028 
       
  2029 		do_action('xmlrpc_call', 'wp.newPage');
       
  2030 
       
  2031 		// Mark this as content for a page.
       
  2032 		$args[3]["post_type"] = 'page';
       
  2033 
       
  2034 		// Let mw_newPost do all of the heavy lifting.
       
  2035 		return($this->mw_newPost($args));
       
  2036 	}
       
  2037 
       
  2038 	/**
       
  2039 	 * Delete page.
       
  2040 	 *
       
  2041 	 * @since 2.2.0
       
  2042 	 *
       
  2043 	 * @param array $args Method parameters.
       
  2044 	 * @return bool True, if success.
       
  2045 	 */
       
  2046 	function wp_deletePage($args) {
       
  2047 		$this->escape($args);
       
  2048 
       
  2049 		$blog_id	= (int) $args[0];
       
  2050 		$username	= $args[1];
       
  2051 		$password	= $args[2];
       
  2052 		$page_id	= (int) $args[3];
       
  2053 
       
  2054 		if ( !$user = $this->login($username, $password) )
       
  2055 			return $this->error;
       
  2056 
       
  2057 		do_action('xmlrpc_call', 'wp.deletePage');
       
  2058 
       
  2059 		// Get the current page based on the page_id and
       
  2060 		// make sure it is a page and not a post.
       
  2061 		$actual_page = wp_get_single_post($page_id, ARRAY_A);
       
  2062 		if ( !$actual_page || ($actual_page['post_type'] != 'page') )
       
  2063 			return(new IXR_Error(404, __('Sorry, no such page.')));
       
  2064 
       
  2065 		// Make sure the user can delete pages.
       
  2066 		if ( !current_user_can('delete_page', $page_id) )
       
  2067 			return(new IXR_Error(401, __('Sorry, you do not have the right to delete this page.')));
       
  2068 
       
  2069 		// Attempt to delete the page.
       
  2070 		$result = wp_delete_post($page_id);
       
  2071 		if ( !$result )
       
  2072 			return(new IXR_Error(500, __('Failed to delete the page.')));
       
  2073 
       
  2074 		do_action( 'xmlrpc_call_success_wp_deletePage', $page_id, $args );
       
  2075 
       
  2076 		return(true);
       
  2077 	}
       
  2078 
       
  2079 	/**
       
  2080 	 * Edit page.
       
  2081 	 *
       
  2082 	 * @since 2.2.0
       
  2083 	 *
       
  2084 	 * @param array $args Method parameters.
       
  2085 	 * @return unknown
       
  2086 	 */
       
  2087 	function wp_editPage($args) {
       
  2088 		// Items not escaped here will be escaped in editPost.
       
  2089 		$blog_id	= (int) $args[0];
       
  2090 		$page_id	= (int) $this->escape($args[1]);
       
  2091 		$username	= $this->escape($args[2]);
       
  2092 		$password	= $this->escape($args[3]);
       
  2093 		$content	= $args[4];
       
  2094 		$publish	= $args[5];
       
  2095 
       
  2096 		if ( !$user = $this->login($username, $password) )
       
  2097 			return $this->error;
       
  2098 
       
  2099 		do_action('xmlrpc_call', 'wp.editPage');
       
  2100 
       
  2101 		// Get the page data and make sure it is a page.
       
  2102 		$actual_page = wp_get_single_post($page_id, ARRAY_A);
       
  2103 		if ( !$actual_page || ($actual_page['post_type'] != 'page') )
       
  2104 			return(new IXR_Error(404, __('Sorry, no such page.')));
       
  2105 
       
  2106 		// Make sure the user is allowed to edit pages.
       
  2107 		if ( !current_user_can('edit_page', $page_id) )
       
  2108 			return(new IXR_Error(401, __('Sorry, you do not have the right to edit this page.')));
       
  2109 
       
  2110 		// Mark this as content for a page.
       
  2111 		$content['post_type'] = 'page';
       
  2112 
       
  2113 		// Arrange args in the way mw_editPost understands.
       
  2114 		$args = array(
       
  2115 			$page_id,
       
  2116 			$username,
       
  2117 			$password,
       
  2118 			$content,
       
  2119 			$publish
       
  2120 		);
       
  2121 
       
  2122 		// Let mw_editPost do all of the heavy lifting.
       
  2123 		return($this->mw_editPost($args));
       
  2124 	}
       
  2125 
       
  2126 	/**
       
  2127 	 * Retrieve page list.
       
  2128 	 *
       
  2129 	 * @since 2.2.0
       
  2130 	 *
       
  2131 	 * @param array $args Method parameters.
       
  2132 	 * @return unknown
       
  2133 	 */
       
  2134 	function wp_getPageList($args) {
       
  2135 		global $wpdb;
       
  2136 
       
  2137 		$this->escape($args);
       
  2138 
       
  2139 		$blog_id				= (int) $args[0];
       
  2140 		$username				= $args[1];
       
  2141 		$password				= $args[2];
       
  2142 
       
  2143 		if ( !$user = $this->login($username, $password) )
       
  2144 			return $this->error;
       
  2145 
       
  2146 		if ( !current_user_can( 'edit_pages' ) )
       
  2147 			return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) );
       
  2148 
       
  2149 		do_action('xmlrpc_call', 'wp.getPageList');
       
  2150 
       
  2151 		// Get list of pages ids and titles
       
  2152 		$page_list = $wpdb->get_results("
       
  2153 			SELECT ID page_id,
       
  2154 				post_title page_title,
       
  2155 				post_parent page_parent_id,
       
  2156 				post_date_gmt,
       
  2157 				post_date,
       
  2158 				post_status
       
  2159 			FROM {$wpdb->posts}
       
  2160 			WHERE post_type = 'page'
       
  2161 			ORDER BY ID
       
  2162 		");
       
  2163 
       
  2164 		// The date needs to be formatted properly.
       
  2165 		$num_pages = count($page_list);
       
  2166 		for ( $i = 0; $i < $num_pages; $i++ ) {
       
  2167 			$page_list[$i]->dateCreated = $this->_convert_date(  $page_list[$i]->post_date );
       
  2168 			$page_list[$i]->date_created_gmt = $this->_convert_date_gmt( $page_list[$i]->post_date_gmt, $page_list[$i]->post_date );
       
  2169 
       
  2170 			unset($page_list[$i]->post_date_gmt);
       
  2171 			unset($page_list[$i]->post_date);
       
  2172 			unset($page_list[$i]->post_status);
       
  2173 		}
       
  2174 
       
  2175 		return($page_list);
       
  2176 	}
       
  2177 
       
  2178 	/**
       
  2179 	 * Retrieve authors list.
       
  2180 	 *
       
  2181 	 * @since 2.2.0
       
  2182 	 *
       
  2183 	 * @param array $args Method parameters.
       
  2184 	 * @return array
       
  2185 	 */
       
  2186 	function wp_getAuthors($args) {
       
  2187 
       
  2188 		$this->escape($args);
       
  2189 
       
  2190 		$blog_id	= (int) $args[0];
       
  2191 		$username	= $args[1];
       
  2192 		$password	= $args[2];
       
  2193 
       
  2194 		if ( !$user = $this->login($username, $password) )
       
  2195 			return $this->error;
       
  2196 
       
  2197 		if ( !current_user_can('edit_posts') )
       
  2198 			return(new IXR_Error(401, __('Sorry, you cannot edit posts on this site.')));
       
  2199 
       
  2200 		do_action('xmlrpc_call', 'wp.getAuthors');
       
  2201 
       
  2202 		$authors = array();
       
  2203 		foreach ( get_users( array( 'fields' => array('ID','user_login','display_name') ) ) as $user ) {
       
  2204 			$authors[] = array(
       
  2205 				'user_id'       => $user->ID,
       
  2206 				'user_login'    => $user->user_login,
       
  2207 				'display_name'  => $user->display_name
       
  2208 			);
       
  2209 		}
       
  2210 
       
  2211 		return $authors;
       
  2212 	}
       
  2213 
       
  2214 	/**
       
  2215 	 * Get list of all tags
       
  2216 	 *
       
  2217 	 * @since 2.7.0
       
  2218 	 *
       
  2219 	 * @param array $args Method parameters.
       
  2220 	 * @return array
       
  2221 	 */
       
  2222 	function wp_getTags( $args ) {
       
  2223 		$this->escape( $args );
       
  2224 
       
  2225 		$blog_id		= (int) $args[0];
       
  2226 		$username		= $args[1];
       
  2227 		$password		= $args[2];
       
  2228 
       
  2229 		if ( !$user = $this->login($username, $password) )
       
  2230 			return $this->error;
       
  2231 
       
  2232 		if ( !current_user_can( 'edit_posts' ) )
       
  2233 			return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view tags.' ) );
       
  2234 
       
  2235 		do_action( 'xmlrpc_call', 'wp.getKeywords' );
       
  2236 
       
  2237 		$tags = array();
       
  2238 
       
  2239 		if ( $all_tags = get_tags() ) {
       
  2240 			foreach( (array) $all_tags as $tag ) {
       
  2241 				$struct['tag_id']			= $tag->term_id;
       
  2242 				$struct['name']				= $tag->name;
       
  2243 				$struct['count']			= $tag->count;
       
  2244 				$struct['slug']				= $tag->slug;
       
  2245 				$struct['html_url']			= esc_html( get_tag_link( $tag->term_id ) );
       
  2246 				$struct['rss_url']			= esc_html( get_tag_feed_link( $tag->term_id ) );
       
  2247 
       
  2248 				$tags[] = $struct;
       
  2249 			}
       
  2250 		}
       
  2251 
       
  2252 		return $tags;
       
  2253 	}
       
  2254 
       
  2255 	/**
       
  2256 	 * Create new category.
       
  2257 	 *
       
  2258 	 * @since 2.2.0
       
  2259 	 *
       
  2260 	 * @param array $args Method parameters.
       
  2261 	 * @return int Category ID.
       
  2262 	 */
       
  2263 	function wp_newCategory($args) {
       
  2264 		$this->escape($args);
       
  2265 
       
  2266 		$blog_id				= (int) $args[0];
       
  2267 		$username				= $args[1];
       
  2268 		$password				= $args[2];
       
  2269 		$category				= $args[3];
       
  2270 
       
  2271 		if ( !$user = $this->login($username, $password) )
       
  2272 			return $this->error;
       
  2273 
       
  2274 		do_action('xmlrpc_call', 'wp.newCategory');
       
  2275 
       
  2276 		// Make sure the user is allowed to add a category.
       
  2277 		if ( !current_user_can('manage_categories') )
       
  2278 			return(new IXR_Error(401, __('Sorry, you do not have the right to add a category.')));
       
  2279 
       
  2280 		// If no slug was provided make it empty so that
       
  2281 		// WordPress will generate one.
       
  2282 		if ( empty($category['slug']) )
       
  2283 			$category['slug'] = '';
       
  2284 
       
  2285 		// If no parent_id was provided make it empty
       
  2286 		// so that it will be a top level page (no parent).
       
  2287 		if ( !isset($category['parent_id']) )
       
  2288 			$category['parent_id'] = '';
       
  2289 
       
  2290 		// If no description was provided make it empty.
       
  2291 		if ( empty($category["description"]) )
       
  2292 			$category["description"] = "";
       
  2293 
       
  2294 		$new_category = array(
       
  2295 			'cat_name'				=> $category['name'],
       
  2296 			'category_nicename'		=> $category['slug'],
       
  2297 			'category_parent'		=> $category['parent_id'],
       
  2298 			'category_description'	=> $category['description']
       
  2299 		);
       
  2300 
       
  2301 		$cat_id = wp_insert_category($new_category, true);
       
  2302 		if ( is_wp_error( $cat_id ) ) {
       
  2303 			if ( 'term_exists' == $cat_id->get_error_code() )
       
  2304 				return (int) $cat_id->get_error_data();
       
  2305 			else
       
  2306 				return(new IXR_Error(500, __('Sorry, the new category failed.')));
       
  2307 		} elseif ( ! $cat_id ) {
       
  2308 			return(new IXR_Error(500, __('Sorry, the new category failed.')));
       
  2309 		}
       
  2310 
       
  2311 		do_action( 'xmlrpc_call_success_wp_newCategory', $cat_id, $args );
       
  2312 
       
  2313 		return $cat_id;
       
  2314 	}
       
  2315 
       
  2316 	/**
       
  2317 	 * Remove category.
       
  2318 	 *
       
  2319 	 * @since 2.5.0
       
  2320 	 *
       
  2321 	 * @param array $args Method parameters.
       
  2322 	 * @return mixed See {@link wp_delete_term()} for return info.
       
  2323 	 */
       
  2324 	function wp_deleteCategory($args) {
       
  2325 		$this->escape($args);
       
  2326 
       
  2327 		$blog_id		= (int) $args[0];
       
  2328 		$username		= $args[1];
       
  2329 		$password		= $args[2];
       
  2330 		$category_id	= (int) $args[3];
       
  2331 
       
  2332 		if ( !$user = $this->login($username, $password) )
       
  2333 			return $this->error;
       
  2334 
       
  2335 		do_action('xmlrpc_call', 'wp.deleteCategory');
       
  2336 
       
  2337 		if ( !current_user_can('manage_categories') )
       
  2338 			return new IXR_Error( 401, __( 'Sorry, you do not have the right to delete a category.' ) );
       
  2339 
       
  2340 		$status = wp_delete_term( $category_id, 'category' );
       
  2341 
       
  2342 		if( true == $status )
       
  2343 			do_action( 'xmlrpc_call_success_wp_deleteCategory', $category_id, $args );
       
  2344 
       
  2345 		return $status;
       
  2346 	}
       
  2347 
       
  2348 	/**
       
  2349 	 * Retrieve category list.
       
  2350 	 *
       
  2351 	 * @since 2.2.0
       
  2352 	 *
       
  2353 	 * @param array $args Method parameters.
       
  2354 	 * @return array
       
  2355 	 */
       
  2356 	function wp_suggestCategories($args) {
       
  2357 		$this->escape($args);
       
  2358 
       
  2359 		$blog_id				= (int) $args[0];
       
  2360 		$username				= $args[1];
       
  2361 		$password				= $args[2];
       
  2362 		$category				= $args[3];
       
  2363 		$max_results			= (int) $args[4];
       
  2364 
       
  2365 		if ( !$user = $this->login($username, $password) )
       
  2366 			return $this->error;
       
  2367 
       
  2368 		if ( !current_user_can( 'edit_posts' ) )
       
  2369 			return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts to this site in order to view categories.' ) );
       
  2370 
       
  2371 		do_action('xmlrpc_call', 'wp.suggestCategories');
       
  2372 
       
  2373 		$category_suggestions = array();
       
  2374 		$args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category);
       
  2375 		foreach ( (array) get_categories($args) as $cat ) {
       
  2376 			$category_suggestions[] = array(
       
  2377 				'category_id'	=> $cat->term_id,
       
  2378 				'category_name'	=> $cat->name
       
  2379 			);
       
  2380 		}
       
  2381 
       
  2382 		return($category_suggestions);
       
  2383 	}
       
  2384 
       
  2385 	/**
       
  2386 	 * Retrieve comment.
       
  2387 	 *
       
  2388 	 * @since 2.7.0
       
  2389 	 *
       
  2390 	 * @param array $args Method parameters.
       
  2391 	 * @return array
       
  2392 	 */
       
  2393 	function wp_getComment($args) {
       
  2394 		$this->escape($args);
       
  2395 
       
  2396 		$blog_id	= (int) $args[0];
       
  2397 		$username	= $args[1];
       
  2398 		$password	= $args[2];
       
  2399 		$comment_id	= (int) $args[3];
       
  2400 
       
  2401 		if ( !$user = $this->login($username, $password) )
       
  2402 			return $this->error;
       
  2403 
       
  2404 		if ( !current_user_can( 'moderate_comments' ) )
       
  2405 			return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
       
  2406 
       
  2407 		do_action('xmlrpc_call', 'wp.getComment');
       
  2408 
       
  2409 		if ( ! $comment = get_comment($comment_id) )
       
  2410 			return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
       
  2411 
       
  2412 		return $this->_prepare_comment( $comment );
       
  2413 	}
       
  2414 
       
  2415 	/**
       
  2416 	 * Retrieve comments.
       
  2417 	 *
       
  2418 	 * Besides the common blog_id, username, and password arguments, it takes a filter
       
  2419 	 * array as last argument.
       
  2420 	 *
       
  2421 	 * Accepted 'filter' keys are 'status', 'post_id', 'offset', and 'number'.
       
  2422 	 *
       
  2423 	 * The defaults are as follows:
       
  2424 	 * - 'status' - Default is ''. Filter by status (e.g., 'approve', 'hold')
       
  2425 	 * - 'post_id' - Default is ''. The post where the comment is posted. Empty string shows all comments.
       
  2426 	 * - 'number' - Default is 10. Total number of media items to retrieve.
       
  2427 	 * - 'offset' - Default is 0. See {@link WP_Query::query()} for more.
       
  2428 	 *
       
  2429 	 * @since 2.7.0
       
  2430 	 *
       
  2431 	 * @param array $args Method parameters.
       
  2432 	 * @return array. Contains a collection of comments. See {@link wp_xmlrpc_server::wp_getComment()} for a description of each item contents
       
  2433 	 */
       
  2434 	function wp_getComments($args) {
       
  2435 		$this->escape($args);
       
  2436 
       
  2437 		$blog_id	= (int) $args[0];
       
  2438 		$username	= $args[1];
       
  2439 		$password	= $args[2];
       
  2440 		$struct		= isset( $args[3] ) ? $args[3] : array();
       
  2441 
       
  2442 		if ( !$user = $this->login($username, $password) )
       
  2443 			return $this->error;
       
  2444 
       
  2445 		if ( !current_user_can( 'moderate_comments' ) )
       
  2446 			return new IXR_Error( 401, __( 'Sorry, you cannot edit comments.' ) );
       
  2447 
       
  2448 		do_action('xmlrpc_call', 'wp.getComments');
       
  2449 
       
  2450 		if ( isset($struct['status']) )
       
  2451 			$status = $struct['status'];
       
  2452 		else
       
  2453 			$status = '';
       
  2454 
       
  2455 		$post_id = '';
       
  2456 		if ( isset($struct['post_id']) )
       
  2457 			$post_id = absint($struct['post_id']);
       
  2458 
       
  2459 		$offset = 0;
       
  2460 		if ( isset($struct['offset']) )
       
  2461 			$offset = absint($struct['offset']);
       
  2462 
       
  2463 		$number = 10;
       
  2464 		if ( isset($struct['number']) )
       
  2465 			$number = absint($struct['number']);
       
  2466 
       
  2467 		$comments = get_comments( array('status' => $status, 'post_id' => $post_id, 'offset' => $offset, 'number' => $number ) );
       
  2468 
       
  2469 		$comments_struct = array();
       
  2470 
       
  2471 		foreach ( $comments as $comment ) {
       
  2472 			$comments_struct[] = $this->_prepare_comment( $comment );
       
  2473 		}
       
  2474 
       
  2475 		return $comments_struct;
       
  2476 	}
       
  2477 
       
  2478 	/**
       
  2479 	 * Delete a comment.
       
  2480 	 *
       
  2481 	 * By default, the comment will be moved to the trash instead of deleted.
       
  2482 	 * See {@link wp_delete_comment()} for more information on
       
  2483 	 * this behavior.
       
  2484 	 *
       
  2485 	 * @since 2.7.0
       
  2486 	 *
       
  2487 	 * @param array $args Method parameters. Contains:
       
  2488 	 *  - blog_id
       
  2489 	 *  - username
       
  2490 	 *  - password
       
  2491 	 *  - comment_id
       
  2492 	 * @return mixed {@link wp_delete_comment()}
       
  2493 	 */
       
  2494 	function wp_deleteComment($args) {
       
  2495 		$this->escape($args);
       
  2496 
       
  2497 		$blog_id	= (int) $args[0];
       
  2498 		$username	= $args[1];
       
  2499 		$password	= $args[2];
       
  2500 		$comment_ID	= (int) $args[3];
       
  2501 
       
  2502 		if ( !$user = $this->login($username, $password) )
       
  2503 			return $this->error;
       
  2504 
       
  2505 		if ( !current_user_can( 'moderate_comments' ) )
       
  2506 			return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
       
  2507 
       
  2508 		if ( ! get_comment($comment_ID) )
       
  2509 			return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
       
  2510 
       
  2511 		if ( !current_user_can( 'edit_comment', $comment_ID ) )
       
  2512 			return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
       
  2513 
       
  2514 		do_action('xmlrpc_call', 'wp.deleteComment');
       
  2515 
       
  2516 		$status = wp_delete_comment( $comment_ID );
       
  2517 
       
  2518 		if( true == $status )
       
  2519 			do_action( 'xmlrpc_call_success_wp_deleteComment', $comment_ID, $args );
       
  2520 
       
  2521 		return $status;
       
  2522 	}
       
  2523 
       
  2524 	/**
       
  2525 	 * Edit comment.
       
  2526 	 *
       
  2527 	 * Besides the common blog_id, username, and password arguments, it takes a
       
  2528 	 * comment_id integer and a content_struct array as last argument.
       
  2529 	 *
       
  2530 	 * The allowed keys in the content_struct array are:
       
  2531 	 *  - 'author'
       
  2532 	 *  - 'author_url'
       
  2533 	 *  - 'author_email'
       
  2534 	 *  - 'content'
       
  2535 	 *  - 'date_created_gmt'
       
  2536 	 *  - 'status'. Common statuses are 'approve', 'hold', 'spam'. See {@link get_comment_statuses()} for more details
       
  2537 	 *
       
  2538 	 * @since 2.7.0
       
  2539 	 *
       
  2540 	 * @param array $args. Contains:
       
  2541 	 *  - blog_id
       
  2542 	 *  - username
       
  2543 	 *  - password
       
  2544 	 *  - comment_id
       
  2545 	 *  - content_struct
       
  2546 	 * @return bool True, on success.
       
  2547 	 */
       
  2548 	function wp_editComment($args) {
       
  2549 		$this->escape($args);
       
  2550 
       
  2551 		$blog_id	= (int) $args[0];
       
  2552 		$username	= $args[1];
       
  2553 		$password	= $args[2];
       
  2554 		$comment_ID	= (int) $args[3];
       
  2555 		$content_struct = $args[4];
       
  2556 
       
  2557 		if ( !$user = $this->login($username, $password) )
       
  2558 			return $this->error;
       
  2559 
       
  2560 		if ( !current_user_can( 'moderate_comments' ) )
       
  2561 			return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
       
  2562 
       
  2563 		if ( ! get_comment($comment_ID) )
       
  2564 			return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
       
  2565 
       
  2566 		if ( !current_user_can( 'edit_comment', $comment_ID ) )
       
  2567 			return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
       
  2568 
       
  2569 		do_action('xmlrpc_call', 'wp.editComment');
       
  2570 
       
  2571 		if ( isset($content_struct['status']) ) {
       
  2572 			$statuses = get_comment_statuses();
       
  2573 			$statuses = array_keys($statuses);
       
  2574 
       
  2575 			if ( ! in_array($content_struct['status'], $statuses) )
       
  2576 				return new IXR_Error( 401, __( 'Invalid comment status.' ) );
       
  2577 			$comment_approved = $content_struct['status'];
       
  2578 		}
       
  2579 
       
  2580 		// Do some timestamp voodoo
       
  2581 		if ( !empty( $content_struct['date_created_gmt'] ) ) {
       
  2582 			// We know this is supposed to be GMT, so we're going to slap that Z on there by force
       
  2583 			$dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z';
       
  2584 			$comment_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
       
  2585 			$comment_date_gmt = iso8601_to_datetime($dateCreated, 'GMT');
       
  2586 		}
       
  2587 
       
  2588 		if ( isset($content_struct['content']) )
       
  2589 			$comment_content = $content_struct['content'];
       
  2590 
       
  2591 		if ( isset($content_struct['author']) )
       
  2592 			$comment_author = $content_struct['author'];
       
  2593 
       
  2594 		if ( isset($content_struct['author_url']) )
       
  2595 			$comment_author_url = $content_struct['author_url'];
       
  2596 
       
  2597 		if ( isset($content_struct['author_email']) )
       
  2598 			$comment_author_email = $content_struct['author_email'];
       
  2599 
       
  2600 		// We've got all the data -- post it:
       
  2601 		$comment = compact('comment_ID', 'comment_content', 'comment_approved', 'comment_date', 'comment_date_gmt', 'comment_author', 'comment_author_email', 'comment_author_url');
       
  2602 
       
  2603 		$result = wp_update_comment($comment);
       
  2604 		if ( is_wp_error( $result ) )
       
  2605 			return new IXR_Error(500, $result->get_error_message());
       
  2606 
       
  2607 		if ( !$result )
       
  2608 			return new IXR_Error(500, __('Sorry, the comment could not be edited. Something wrong happened.'));
       
  2609 
       
  2610 		do_action( 'xmlrpc_call_success_wp_editComment', $comment_ID, $args );
       
  2611 
       
  2612 		return true;
       
  2613 	}
       
  2614 
       
  2615 	/**
       
  2616 	 * Create new comment.
       
  2617 	 *
       
  2618 	 * @since 2.7.0
       
  2619 	 *
       
  2620 	 * @param array $args Method parameters.
       
  2621 	 * @return mixed {@link wp_new_comment()}
       
  2622 	 */
       
  2623 	function wp_newComment($args) {
       
  2624 		global $wpdb;
       
  2625 
       
  2626 		$this->escape($args);
       
  2627 
       
  2628 		$blog_id	= (int) $args[0];
       
  2629 		$username	= $args[1];
       
  2630 		$password	= $args[2];
       
  2631 		$post		= $args[3];
       
  2632 		$content_struct = $args[4];
       
  2633 
       
  2634 		$allow_anon = apply_filters('xmlrpc_allow_anonymous_comments', false);
       
  2635 
       
  2636 		$user = $this->login($username, $password);
       
  2637 
       
  2638 		if ( !$user ) {
       
  2639 			$logged_in = false;
       
  2640 			if ( $allow_anon && get_option('comment_registration') )
       
  2641 				return new IXR_Error( 403, __( 'You must be registered to comment' ) );
       
  2642 			else if ( !$allow_anon )
       
  2643 				return $this->error;
       
  2644 		} else {
       
  2645 			$logged_in = true;
       
  2646 		}
       
  2647 
       
  2648 		if ( is_numeric($post) )
       
  2649 			$post_id = absint($post);
       
  2650 		else
       
  2651 			$post_id = url_to_postid($post);
       
  2652 
       
  2653 		if ( ! $post_id )
       
  2654 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  2655 
       
  2656 		if ( ! get_post($post_id) )
       
  2657 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  2658 
       
  2659 		$comment['comment_post_ID'] = $post_id;
       
  2660 
       
  2661 		if ( $logged_in ) {
       
  2662 			$comment['comment_author'] = $wpdb->escape( $user->display_name );
       
  2663 			$comment['comment_author_email'] = $wpdb->escape( $user->user_email );
       
  2664 			$comment['comment_author_url'] = $wpdb->escape( $user->user_url );
       
  2665 			$comment['user_ID'] = $user->ID;
       
  2666 		} else {
       
  2667 			$comment['comment_author'] = '';
       
  2668 			if ( isset($content_struct['author']) )
       
  2669 				$comment['comment_author'] = $content_struct['author'];
       
  2670 
       
  2671 			$comment['comment_author_email'] = '';
       
  2672 			if ( isset($content_struct['author_email']) )
       
  2673 				$comment['comment_author_email'] = $content_struct['author_email'];
       
  2674 
       
  2675 			$comment['comment_author_url'] = '';
       
  2676 			if ( isset($content_struct['author_url']) )
       
  2677 				$comment['comment_author_url'] = $content_struct['author_url'];
       
  2678 
       
  2679 			$comment['user_ID'] = 0;
       
  2680 
       
  2681 			if ( get_option('require_name_email') ) {
       
  2682 				if ( 6 > strlen($comment['comment_author_email']) || '' == $comment['comment_author'] )
       
  2683 					return new IXR_Error( 403, __( 'Comment author name and email are required' ) );
       
  2684 				elseif ( !is_email($comment['comment_author_email']) )
       
  2685 					return new IXR_Error( 403, __( 'A valid email address is required' ) );
       
  2686 			}
       
  2687 		}
       
  2688 
       
  2689 		$comment['comment_parent'] = isset($content_struct['comment_parent']) ? absint($content_struct['comment_parent']) : 0;
       
  2690 
       
  2691 		$comment['comment_content'] =  isset($content_struct['content']) ? $content_struct['content'] : null;
       
  2692 
       
  2693 		do_action('xmlrpc_call', 'wp.newComment');
       
  2694 
       
  2695 		$comment_ID = wp_new_comment( $comment );
       
  2696 
       
  2697 		do_action( 'xmlrpc_call_success_wp_newComment', $comment_ID, $args );
       
  2698 
       
  2699 		return $comment_ID;
       
  2700 	}
       
  2701 
       
  2702 	/**
       
  2703 	 * Retrieve all of the comment status.
       
  2704 	 *
       
  2705 	 * @since 2.7.0
       
  2706 	 *
       
  2707 	 * @param array $args Method parameters.
       
  2708 	 * @return array
       
  2709 	 */
       
  2710 	function wp_getCommentStatusList($args) {
       
  2711 		$this->escape( $args );
       
  2712 
       
  2713 		$blog_id	= (int) $args[0];
       
  2714 		$username	= $args[1];
       
  2715 		$password	= $args[2];
       
  2716 
       
  2717 		if ( !$user = $this->login($username, $password) )
       
  2718 			return $this->error;
       
  2719 
       
  2720 		if ( !current_user_can( 'moderate_comments' ) )
       
  2721 			return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
       
  2722 
       
  2723 		do_action('xmlrpc_call', 'wp.getCommentStatusList');
       
  2724 
       
  2725 		return get_comment_statuses();
       
  2726 	}
       
  2727 
       
  2728 	/**
       
  2729 	 * Retrieve comment count.
       
  2730 	 *
       
  2731 	 * @since 2.5.0
       
  2732 	 *
       
  2733 	 * @param array $args Method parameters.
       
  2734 	 * @return array
       
  2735 	 */
       
  2736 	function wp_getCommentCount( $args ) {
       
  2737 		$this->escape($args);
       
  2738 
       
  2739 		$blog_id	= (int) $args[0];
       
  2740 		$username	= $args[1];
       
  2741 		$password	= $args[2];
       
  2742 		$post_id	= (int) $args[3];
       
  2743 
       
  2744 		if ( !$user = $this->login($username, $password) )
       
  2745 			return $this->error;
       
  2746 
       
  2747 		if ( !current_user_can( 'edit_posts' ) )
       
  2748 			return new IXR_Error( 403, __( 'You are not allowed access to details about comments.' ) );
       
  2749 
       
  2750 		do_action('xmlrpc_call', 'wp.getCommentCount');
       
  2751 
       
  2752 		$count = wp_count_comments( $post_id );
       
  2753 		return array(
       
  2754 			'approved' => $count->approved,
       
  2755 			'awaiting_moderation' => $count->moderated,
       
  2756 			'spam' => $count->spam,
       
  2757 			'total_comments' => $count->total_comments
       
  2758 		);
       
  2759 	}
       
  2760 
       
  2761 	/**
       
  2762 	 * Retrieve post statuses.
       
  2763 	 *
       
  2764 	 * @since 2.5.0
       
  2765 	 *
       
  2766 	 * @param array $args Method parameters.
       
  2767 	 * @return array
       
  2768 	 */
       
  2769 	function wp_getPostStatusList( $args ) {
       
  2770 		$this->escape( $args );
       
  2771 
       
  2772 		$blog_id	= (int) $args[0];
       
  2773 		$username	= $args[1];
       
  2774 		$password	= $args[2];
       
  2775 
       
  2776 		if ( !$user = $this->login($username, $password) )
       
  2777 			return $this->error;
       
  2778 
       
  2779 		if ( !current_user_can( 'edit_posts' ) )
       
  2780 			return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
       
  2781 
       
  2782 		do_action('xmlrpc_call', 'wp.getPostStatusList');
       
  2783 
       
  2784 		return get_post_statuses();
       
  2785 	}
       
  2786 
       
  2787 	/**
       
  2788 	 * Retrieve page statuses.
       
  2789 	 *
       
  2790 	 * @since 2.5.0
       
  2791 	 *
       
  2792 	 * @param array $args Method parameters.
       
  2793 	 * @return array
       
  2794 	 */
       
  2795 	function wp_getPageStatusList( $args ) {
       
  2796 		$this->escape( $args );
       
  2797 
       
  2798 		$blog_id	= (int) $args[0];
       
  2799 		$username	= $args[1];
       
  2800 		$password	= $args[2];
       
  2801 
       
  2802 		if ( !$user = $this->login($username, $password) )
       
  2803 			return $this->error;
       
  2804 
       
  2805 		if ( !current_user_can( 'edit_pages' ) )
       
  2806 			return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
       
  2807 
       
  2808 		do_action('xmlrpc_call', 'wp.getPageStatusList');
       
  2809 
       
  2810 		return get_page_statuses();
       
  2811 	}
       
  2812 
       
  2813 	/**
       
  2814 	 * Retrieve page templates.
       
  2815 	 *
       
  2816 	 * @since 2.6.0
       
  2817 	 *
       
  2818 	 * @param array $args Method parameters.
       
  2819 	 * @return array
       
  2820 	 */
       
  2821 	function wp_getPageTemplates( $args ) {
       
  2822 		$this->escape( $args );
       
  2823 
       
  2824 		$blog_id	= (int) $args[0];
       
  2825 		$username	= $args[1];
       
  2826 		$password	= $args[2];
       
  2827 
       
  2828 		if ( !$user = $this->login($username, $password) )
       
  2829 			return $this->error;
       
  2830 
       
  2831 		if ( !current_user_can( 'edit_pages' ) )
       
  2832 			return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
       
  2833 
       
  2834 		$templates = get_page_templates();
       
  2835 		$templates['Default'] = 'default';
       
  2836 
       
  2837 		return $templates;
       
  2838 	}
       
  2839 
       
  2840 	/**
       
  2841 	 * Retrieve blog options.
       
  2842 	 *
       
  2843 	 * @since 2.6.0
       
  2844 	 *
       
  2845 	 * @param array $args Method parameters.
       
  2846 	 * @return array
       
  2847 	 */
       
  2848 	function wp_getOptions( $args ) {
       
  2849 		$this->escape( $args );
       
  2850 
       
  2851 		$blog_id	= (int) $args[0];
       
  2852 		$username	= $args[1];
       
  2853 		$password	= $args[2];
       
  2854 		$options	= isset( $args[3] ) ? (array) $args[3] : array();
       
  2855 
       
  2856 		if ( !$user = $this->login($username, $password) )
       
  2857 			return $this->error;
       
  2858 
       
  2859 		// If no specific options where asked for, return all of them
       
  2860 		if ( count( $options ) == 0 )
       
  2861 			$options = array_keys($this->blog_options);
       
  2862 
       
  2863 		return $this->_getOptions($options);
       
  2864 	}
       
  2865 
       
  2866 	/**
       
  2867 	 * Retrieve blog options value from list.
       
  2868 	 *
       
  2869 	 * @since 2.6.0
       
  2870 	 *
       
  2871 	 * @param array $options Options to retrieve.
       
  2872 	 * @return array
       
  2873 	 */
       
  2874 	function _getOptions($options) {
       
  2875 		$data = array();
       
  2876 		foreach ( $options as $option ) {
       
  2877 			if ( array_key_exists( $option, $this->blog_options ) ) {
       
  2878 				$data[$option] = $this->blog_options[$option];
       
  2879 				//Is the value static or dynamic?
       
  2880 				if ( isset( $data[$option]['option'] ) ) {
       
  2881 					$data[$option]['value'] = get_option( $data[$option]['option'] );
       
  2882 					unset($data[$option]['option']);
       
  2883 				}
       
  2884 			}
       
  2885 		}
       
  2886 
       
  2887 		return $data;
       
  2888 	}
       
  2889 
       
  2890 	/**
       
  2891 	 * Update blog options.
       
  2892 	 *
       
  2893 	 * @since 2.6.0
       
  2894 	 *
       
  2895 	 * @param array $args Method parameters.
       
  2896 	 * @return unknown
       
  2897 	 */
       
  2898 	function wp_setOptions( $args ) {
       
  2899 		$this->escape( $args );
       
  2900 
       
  2901 		$blog_id	= (int) $args[0];
       
  2902 		$username	= $args[1];
       
  2903 		$password	= $args[2];
       
  2904 		$options	= (array) $args[3];
       
  2905 
       
  2906 		if ( !$user = $this->login($username, $password) )
       
  2907 			return $this->error;
       
  2908 
       
  2909 		if ( !current_user_can( 'manage_options' ) )
       
  2910 			return new IXR_Error( 403, __( 'You are not allowed to update options.' ) );
       
  2911 
       
  2912 		foreach ( $options as $o_name => $o_value ) {
       
  2913 			$option_names[] = $o_name;
       
  2914 			if ( !array_key_exists( $o_name, $this->blog_options ) )
       
  2915 				continue;
       
  2916 
       
  2917 			if ( $this->blog_options[$o_name]['readonly'] == true )
       
  2918 				continue;
       
  2919 
       
  2920 			update_option( $this->blog_options[$o_name]['option'], $o_value );
       
  2921 		}
       
  2922 
       
  2923 		//Now return the updated values
       
  2924 		return $this->_getOptions($option_names);
       
  2925 	}
       
  2926 
       
  2927 	/**
       
  2928 	 * Retrieve a media item by ID
       
  2929 	 *
       
  2930 	 * @since 3.1.0
       
  2931 	 *
       
  2932 	 * @param array $args Method parameters. Contains:
       
  2933 	 *  - blog_id
       
  2934 	 *  - username
       
  2935 	 *  - password
       
  2936 	 *  - attachment_id
       
  2937 	 * @return array. Associative array containing:
       
  2938 	 *  - 'date_created_gmt'
       
  2939 	 *  - 'parent'
       
  2940 	 *  - 'link'
       
  2941 	 *  - 'thumbnail'
       
  2942 	 *  - 'title'
       
  2943 	 *  - 'caption'
       
  2944 	 *  - 'description'
       
  2945 	 *  - 'metadata'
       
  2946 	 */
       
  2947 	function wp_getMediaItem($args) {
       
  2948 		$this->escape($args);
       
  2949 
       
  2950 		$blog_id		= (int) $args[0];
       
  2951 		$username		= $args[1];
       
  2952 		$password		= $args[2];
       
  2953 		$attachment_id	= (int) $args[3];
       
  2954 
       
  2955 		if ( !$user = $this->login($username, $password) )
       
  2956 			return $this->error;
       
  2957 
       
  2958 		if ( !current_user_can( 'upload_files' ) )
       
  2959 			return new IXR_Error( 403, __( 'You do not have permission to upload files.' ) );
       
  2960 
       
  2961 		do_action('xmlrpc_call', 'wp.getMediaItem');
       
  2962 
       
  2963 		if ( ! $attachment = get_post($attachment_id) )
       
  2964 			return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
       
  2965 
       
  2966 		return $this->_prepare_media_item( $attachment );
       
  2967 	}
       
  2968 
       
  2969 	/**
       
  2970 	 * Retrieves a collection of media library items (or attachments)
       
  2971 	 *
       
  2972 	 * Besides the common blog_id, username, and password arguments, it takes a filter
       
  2973 	 * array as last argument.
       
  2974 	 *
       
  2975 	 * Accepted 'filter' keys are 'parent_id', 'mime_type', 'offset', and 'number'.
       
  2976 	 *
       
  2977 	 * The defaults are as follows:
       
  2978 	 * - 'number' - Default is 5. Total number of media items to retrieve.
       
  2979 	 * - 'offset' - Default is 0. See {@link WP_Query::query()} for more.
       
  2980 	 * - 'parent_id' - Default is ''. The post where the media item is attached. Empty string shows all media items. 0 shows unattached media items.
       
  2981 	 * - 'mime_type' - Default is ''. Filter by mime type (e.g., 'image/jpeg', 'application/pdf')
       
  2982 	 *
       
  2983 	 * @since 3.1.0
       
  2984 	 *
       
  2985 	 * @param array $args Method parameters. Contains:
       
  2986 	 *  - blog_id
       
  2987 	 *  - username
       
  2988 	 *  - password
       
  2989 	 *  - filter
       
  2990 	 * @return array. Contains a collection of media items. See {@link wp_xmlrpc_server::wp_getMediaItem()} for a description of each item contents
       
  2991 	 */
       
  2992 	function wp_getMediaLibrary($args) {
       
  2993 		$this->escape($args);
       
  2994 
       
  2995 		$blog_id	= (int) $args[0];
       
  2996 		$username	= $args[1];
       
  2997 		$password	= $args[2];
       
  2998 		$struct		= isset( $args[3] ) ? $args[3] : array() ;
       
  2999 
       
  3000 		if ( !$user = $this->login($username, $password) )
       
  3001 			return $this->error;
       
  3002 
       
  3003 		if ( !current_user_can( 'upload_files' ) )
       
  3004 			return new IXR_Error( 401, __( 'You do not have permission to upload files.' ) );
       
  3005 
       
  3006 		do_action('xmlrpc_call', 'wp.getMediaLibrary');
       
  3007 
       
  3008 		$parent_id = ( isset($struct['parent_id']) ) ? absint($struct['parent_id']) : '' ;
       
  3009 		$mime_type = ( isset($struct['mime_type']) ) ? $struct['mime_type'] : '' ;
       
  3010 		$offset = ( isset($struct['offset']) ) ? absint($struct['offset']) : 0 ;
       
  3011 		$number = ( isset($struct['number']) ) ? absint($struct['number']) : -1 ;
       
  3012 
       
  3013 		$attachments = get_posts( array('post_type' => 'attachment', 'post_parent' => $parent_id, 'offset' => $offset, 'numberposts' => $number, 'post_mime_type' => $mime_type ) );
       
  3014 
       
  3015 		$attachments_struct = array();
       
  3016 
       
  3017 		foreach ($attachments as $attachment )
       
  3018 			$attachments_struct[] = $this->_prepare_media_item( $attachment );
       
  3019 
       
  3020 		return $attachments_struct;
       
  3021 	}
       
  3022 
       
  3023 	/**
       
  3024 	  * Retrieves a list of post formats used by the site
       
  3025 	  *
       
  3026 	  * @since 3.1
       
  3027 	  *
       
  3028 	  * @param array $args Method parameters. Contains:
       
  3029 	  *  - blog_id
       
  3030 	  *  - username
       
  3031 	  *  - password
       
  3032 	  * @return array
       
  3033 	  */
       
  3034 	function wp_getPostFormats( $args ) {
       
  3035 		$this->escape( $args );
       
  3036 
       
  3037 		$blog_id = (int) $args[0];
       
  3038 		$username = $args[1];
       
  3039 		$password = $args[2];
       
  3040 
       
  3041 		if ( !$user = $this->login( $username, $password ) )
       
  3042 			return $this->error;
       
  3043 
       
  3044 		if ( !current_user_can( 'edit_posts' ) )
       
  3045 			return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
       
  3046 
       
  3047 		do_action( 'xmlrpc_call', 'wp.getPostFormats' );
       
  3048 
       
  3049 		$formats = get_post_format_strings();
       
  3050 
       
  3051 		# find out if they want a list of currently supports formats
       
  3052 		if ( isset( $args[3] ) && is_array( $args[3] ) ) {
       
  3053 			if ( $args[3]['show-supported'] ) {
       
  3054 				if ( current_theme_supports( 'post-formats' ) ) {
       
  3055 					$supported = get_theme_support( 'post-formats' );
       
  3056 
       
  3057 					$data['all'] = $formats;
       
  3058 					$data['supported'] = $supported[0];
       
  3059 
       
  3060 					$formats = $data;
       
  3061 				}
       
  3062 			}
       
  3063 		}
       
  3064 
       
  3065 		return $formats;
       
  3066 	}
       
  3067 
       
  3068 	/**
       
  3069 	 * Retrieves a post type
       
  3070 	 *
       
  3071 	 * @since 3.4.0
       
  3072 	 *
       
  3073 	 * @uses get_post_type_object()
       
  3074 	 * @param array $args Method parameters. Contains:
       
  3075 	 *  - int     $blog_id
       
  3076 	 *  - string  $username
       
  3077 	 *  - string  $password
       
  3078 	 *  - string  $post_type_name
       
  3079 	 *  - array   $fields
       
  3080 	 * @return array contains:
       
  3081 	 *  - 'labels'
       
  3082 	 *  - 'description'
       
  3083 	 *  - 'capability_type'
       
  3084 	 *  - 'cap'
       
  3085 	 *  - 'map_meta_cap'
       
  3086 	 *  - 'hierarchical'
       
  3087 	 *  - 'menu_position'
       
  3088 	 *  - 'taxonomies'
       
  3089 	 *  - 'supports'
       
  3090 	 */
       
  3091 	function wp_getPostType( $args ) {
       
  3092 		if ( ! $this->minimum_args( $args, 4 ) )
       
  3093 			return $this->error;
       
  3094 
       
  3095 		$this->escape( $args );
       
  3096 
       
  3097 		$blog_id        = (int) $args[0];
       
  3098 		$username       = $args[1];
       
  3099 		$password       = $args[2];
       
  3100 		$post_type_name = $args[3];
       
  3101 
       
  3102 		if ( isset( $args[4] ) )
       
  3103 			$fields = $args[4];
       
  3104 		else
       
  3105 			$fields = apply_filters( 'xmlrpc_default_posttype_fields', array( 'labels', 'cap', 'taxonomies' ), 'wp.getPostType' );
       
  3106 
       
  3107 		if ( !$user = $this->login( $username, $password ) )
       
  3108 			return $this->error;
       
  3109 
       
  3110 		do_action( 'xmlrpc_call', 'wp.getPostType' );
       
  3111 
       
  3112 		if( ! post_type_exists( $post_type_name ) )
       
  3113 			return new IXR_Error( 403, __( 'Invalid post type' ) );
       
  3114 
       
  3115 		$post_type = get_post_type_object( $post_type_name );
       
  3116 
       
  3117 		if( ! current_user_can( $post_type->cap->edit_posts ) )
       
  3118 			return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit this post type.' ) );
       
  3119 
       
  3120 		return $this->_prepare_post_type( $post_type, $fields );
       
  3121 	}
       
  3122 
       
  3123 	/**
       
  3124 	 * Retrieves a post types
       
  3125 	 *
       
  3126 	 * @since 3.4.0
       
  3127 	 *
       
  3128 	 * @uses get_post_types()
       
  3129 	 * @param array $args Method parameters. Contains:
       
  3130 	 *  - int     $blog_id
       
  3131 	 *  - string  $username
       
  3132 	 *  - string  $password
       
  3133 	 *  - array   $filter
       
  3134 	 *  - array   $fields
       
  3135 	 * @return array
       
  3136 	 */
       
  3137 	function wp_getPostTypes( $args ) {
       
  3138 		if ( ! $this->minimum_args( $args, 3 ) )
       
  3139 			return $this->error;
       
  3140 
       
  3141 		$this->escape( $args );
       
  3142 
       
  3143 		$blog_id            = (int) $args[0];
       
  3144 		$username           = $args[1];
       
  3145 		$password           = $args[2];
       
  3146 		$filter             = isset( $args[3] ) ? $args[3] : array( 'public' => true );
       
  3147 
       
  3148 		if ( isset( $args[4] ) )
       
  3149 			$fields = $args[4];
       
  3150 		else
       
  3151 			$fields = apply_filters( 'xmlrpc_default_posttype_fields', array( 'labels', 'cap', 'taxonomies' ), 'wp.getPostTypes' );
       
  3152 
       
  3153 		if ( ! $user = $this->login( $username, $password ) )
       
  3154 			return $this->error;
       
  3155 
       
  3156 		do_action( 'xmlrpc_call', 'wp.getPostTypes' );
       
  3157 
       
  3158 		$post_types = get_post_types( $filter, 'objects' );
       
  3159 
       
  3160 		$struct = array();
       
  3161 
       
  3162 		foreach( $post_types as $post_type ) {
       
  3163 			if( ! current_user_can( $post_type->cap->edit_posts ) )
       
  3164 				continue;
       
  3165 
       
  3166 			$struct[$post_type->name] = $this->_prepare_post_type( $post_type, $fields );
       
  3167 		}
       
  3168 
       
  3169 		return $struct;
       
  3170 	}
       
  3171 
       
  3172 	/* Blogger API functions.
       
  3173 	 * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/
       
  3174 	 */
       
  3175 
       
  3176 	/**
       
  3177 	 * Retrieve blogs that user owns.
       
  3178 	 *
       
  3179 	 * Will make more sense once we support multiple blogs.
       
  3180 	 *
       
  3181 	 * @since 1.5.0
       
  3182 	 *
       
  3183 	 * @param array $args Method parameters.
       
  3184 	 * @return array
       
  3185 	 */
       
  3186 	function blogger_getUsersBlogs($args) {
       
  3187 		if ( is_multisite() )
       
  3188 			return $this->_multisite_getUsersBlogs($args);
       
  3189 
       
  3190 		$this->escape($args);
       
  3191 
       
  3192 		$username = $args[1];
       
  3193 		$password  = $args[2];
       
  3194 
       
  3195 		if ( !$user = $this->login($username, $password) )
       
  3196 			return $this->error;
       
  3197 
       
  3198 		do_action('xmlrpc_call', 'blogger.getUsersBlogs');
       
  3199 
       
  3200 		$is_admin = current_user_can('manage_options');
       
  3201 
       
  3202 		$struct = array(
       
  3203 			'isAdmin'  => $is_admin,
       
  3204 			'url'      => get_option('home') . '/',
       
  3205 			'blogid'   => '1',
       
  3206 			'blogName' => get_option('blogname'),
       
  3207 			'xmlrpc'   => site_url( 'xmlrpc.php' )
       
  3208 		);
       
  3209 
       
  3210 		return array($struct);
       
  3211 	}
       
  3212 
       
  3213 	/**
       
  3214 	 * Private function for retrieving a users blogs for multisite setups
       
  3215 	 *
       
  3216 	 * @access protected
       
  3217 	 */
       
  3218 	function _multisite_getUsersBlogs($args) {
       
  3219 		global $current_blog;
       
  3220 		$domain = $current_blog->domain;
       
  3221 		$path = $current_blog->path . 'xmlrpc.php';
       
  3222 		$protocol = is_ssl() ? 'https' : 'http';
       
  3223 
       
  3224 		$rpc = new IXR_Client("$protocol://{$domain}{$path}");
       
  3225 		$rpc->query('wp.getUsersBlogs', $args[1], $args[2]);
       
  3226 		$blogs = $rpc->getResponse();
       
  3227 
       
  3228 		if ( isset($blogs['faultCode']) )
       
  3229 			return new IXR_Error($blogs['faultCode'], $blogs['faultString']);
       
  3230 
       
  3231 		if ( $_SERVER['HTTP_HOST'] == $domain && $_SERVER['REQUEST_URI'] == $path ) {
       
  3232 			return $blogs;
       
  3233 		} else {
       
  3234 			foreach ( (array) $blogs as $blog ) {
       
  3235 				if ( strpos($blog['url'], $_SERVER['HTTP_HOST']) )
       
  3236 					return array($blog);
       
  3237 			}
       
  3238 			return array();
       
  3239 		}
       
  3240 	}
       
  3241 
       
  3242 	/**
       
  3243 	 * Retrieve user's data.
       
  3244 	 *
       
  3245 	 * Gives your client some info about you, so you don't have to.
       
  3246 	 *
       
  3247 	 * @since 1.5.0
       
  3248 	 *
       
  3249 	 * @param array $args Method parameters.
       
  3250 	 * @return array
       
  3251 	 */
       
  3252 	function blogger_getUserInfo($args) {
       
  3253 
       
  3254 		$this->escape($args);
       
  3255 
       
  3256 		$username = $args[1];
       
  3257 		$password  = $args[2];
       
  3258 
       
  3259 		if ( !$user = $this->login($username, $password) )
       
  3260 			return $this->error;
       
  3261 
       
  3262 		if ( !current_user_can( 'edit_posts' ) )
       
  3263 			return new IXR_Error( 401, __( 'Sorry, you do not have access to user data on this site.' ) );
       
  3264 
       
  3265 		do_action('xmlrpc_call', 'blogger.getUserInfo');
       
  3266 
       
  3267 		$struct = array(
       
  3268 			'nickname'  => $user->nickname,
       
  3269 			'userid'    => $user->ID,
       
  3270 			'url'       => $user->user_url,
       
  3271 			'lastname'  => $user->last_name,
       
  3272 			'firstname' => $user->first_name
       
  3273 		);
       
  3274 
       
  3275 		return $struct;
       
  3276 	}
       
  3277 
       
  3278 	/**
       
  3279 	 * Retrieve post.
       
  3280 	 *
       
  3281 	 * @since 1.5.0
       
  3282 	 *
       
  3283 	 * @param array $args Method parameters.
       
  3284 	 * @return array
       
  3285 	 */
       
  3286 	function blogger_getPost($args) {
       
  3287 
       
  3288 		$this->escape($args);
       
  3289 
       
  3290 		$post_ID    = (int) $args[1];
       
  3291 		$username = $args[2];
       
  3292 		$password  = $args[3];
       
  3293 
       
  3294 		if ( !$user = $this->login($username, $password) )
       
  3295 			return $this->error;
       
  3296 
       
  3297 		$post_data = wp_get_single_post($post_ID, ARRAY_A);
       
  3298 		if ( ! $post_data )
       
  3299 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  3300 
       
  3301 		if ( !current_user_can( 'edit_post', $post_ID ) )
       
  3302 			return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
       
  3303 
       
  3304 		do_action('xmlrpc_call', 'blogger.getPost');
       
  3305 
       
  3306 		$categories = implode(',', wp_get_post_categories($post_ID));
       
  3307 
       
  3308 		$content  = '<title>'.stripslashes($post_data['post_title']).'</title>';
       
  3309 		$content .= '<category>'.$categories.'</category>';
       
  3310 		$content .= stripslashes($post_data['post_content']);
       
  3311 
       
  3312 		$struct = array(
       
  3313 			'userid'    => $post_data['post_author'],
       
  3314 			'dateCreated' => $this->_convert_date( $post_data['post_date'] ),
       
  3315 			'content'     => $content,
       
  3316 			'postid'  => (string) $post_data['ID']
       
  3317 		);
       
  3318 
       
  3319 		return $struct;
       
  3320 	}
       
  3321 
       
  3322 	/**
       
  3323 	 * Retrieve list of recent posts.
       
  3324 	 *
       
  3325 	 * @since 1.5.0
       
  3326 	 *
       
  3327 	 * @param array $args Method parameters.
       
  3328 	 * @return array
       
  3329 	 */
       
  3330 	function blogger_getRecentPosts($args) {
       
  3331 
       
  3332 		$this->escape($args);
       
  3333 
       
  3334 		// $args[0] = appkey - ignored
       
  3335 		$blog_ID    = (int) $args[1]; /* though we don't use it yet */
       
  3336 		$username = $args[2];
       
  3337 		$password  = $args[3];
       
  3338 		if ( isset( $args[4] ) )
       
  3339 			$query = array( 'numberposts' => absint( $args[4] ) );
       
  3340 		else
       
  3341 			$query = array();
       
  3342 
       
  3343 		if ( !$user = $this->login($username, $password) )
       
  3344 			return $this->error;
       
  3345 
       
  3346 		do_action('xmlrpc_call', 'blogger.getRecentPosts');
       
  3347 
       
  3348 		$posts_list = wp_get_recent_posts( $query );
       
  3349 
       
  3350 		if ( !$posts_list ) {
       
  3351 			$this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
       
  3352 			return $this->error;
       
  3353 		}
       
  3354 
       
  3355 		foreach ($posts_list as $entry) {
       
  3356 			if ( !current_user_can( 'edit_post', $entry['ID'] ) )
       
  3357 				continue;
       
  3358 
       
  3359 			$post_date  = $this->_convert_date( $entry['post_date'] );
       
  3360 			$categories = implode(',', wp_get_post_categories($entry['ID']));
       
  3361 
       
  3362 			$content  = '<title>'.stripslashes($entry['post_title']).'</title>';
       
  3363 			$content .= '<category>'.$categories.'</category>';
       
  3364 			$content .= stripslashes($entry['post_content']);
       
  3365 
       
  3366 			$struct[] = array(
       
  3367 				'userid' => $entry['post_author'],
       
  3368 				'dateCreated' => $post_date,
       
  3369 				'content' => $content,
       
  3370 				'postid' => (string) $entry['ID'],
       
  3371 			);
       
  3372 
       
  3373 		}
       
  3374 
       
  3375 		$recent_posts = array();
       
  3376 		for ( $j=0; $j<count($struct); $j++ ) {
       
  3377 			array_push($recent_posts, $struct[$j]);
       
  3378 		}
       
  3379 
       
  3380 		return $recent_posts;
       
  3381 	}
       
  3382 
       
  3383 	/**
       
  3384 	 * Retrieve blog_filename content.
       
  3385 	 *
       
  3386 	 * @since 1.5.0
       
  3387 	 *
       
  3388 	 * @param array $args Method parameters.
       
  3389 	 * @return string
       
  3390 	 */
       
  3391 	function blogger_getTemplate($args) {
       
  3392 
       
  3393 		$this->escape($args);
       
  3394 
       
  3395 		$blog_ID    = (int) $args[1];
       
  3396 		$username = $args[2];
       
  3397 		$password  = $args[3];
       
  3398 		$template   = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */
       
  3399 
       
  3400 		if ( !$user = $this->login($username, $password) )
       
  3401 			return $this->error;
       
  3402 
       
  3403 		do_action('xmlrpc_call', 'blogger.getTemplate');
       
  3404 
       
  3405 		if ( !current_user_can('edit_themes') )
       
  3406 			return new IXR_Error(401, __('Sorry, this user cannot edit the template.'));
       
  3407 
       
  3408 		/* warning: here we make the assumption that the blog's URL is on the same server */
       
  3409 		$filename = get_option('home') . '/';
       
  3410 		$filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
       
  3411 
       
  3412 		$f = fopen($filename, 'r');
       
  3413 		$content = fread($f, filesize($filename));
       
  3414 		fclose($f);
       
  3415 
       
  3416 		/* so it is actually editable with a windows/mac client */
       
  3417 		// 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);
       
  3418 
       
  3419 		return $content;
       
  3420 	}
       
  3421 
       
  3422 	/**
       
  3423 	 * Updates the content of blog_filename.
       
  3424 	 *
       
  3425 	 * @since 1.5.0
       
  3426 	 *
       
  3427 	 * @param array $args Method parameters.
       
  3428 	 * @return bool True when done.
       
  3429 	 */
       
  3430 	function blogger_setTemplate($args) {
       
  3431 
       
  3432 		$this->escape($args);
       
  3433 
       
  3434 		$blog_ID    = (int) $args[1];
       
  3435 		$username = $args[2];
       
  3436 		$password  = $args[3];
       
  3437 		$content    = $args[4];
       
  3438 		$template   = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */
       
  3439 
       
  3440 		if ( !$user = $this->login($username, $password) )
       
  3441 			return $this->error;
       
  3442 
       
  3443 		do_action('xmlrpc_call', 'blogger.setTemplate');
       
  3444 
       
  3445 		if ( !current_user_can('edit_themes') )
       
  3446 			return new IXR_Error(401, __('Sorry, this user cannot edit the template.'));
       
  3447 
       
  3448 		/* warning: here we make the assumption that the blog's URL is on the same server */
       
  3449 		$filename = get_option('home') . '/';
       
  3450 		$filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
       
  3451 
       
  3452 		if ($f = fopen($filename, 'w+')) {
       
  3453 			fwrite($f, $content);
       
  3454 			fclose($f);
       
  3455 		} else {
       
  3456 			return new IXR_Error(500, __('Either the file is not writable, or something wrong happened. The file has not been updated.'));
       
  3457 		}
       
  3458 
       
  3459 		return true;
       
  3460 	}
       
  3461 
       
  3462 	/**
       
  3463 	 * Create new post.
       
  3464 	 *
       
  3465 	 * @since 1.5.0
       
  3466 	 *
       
  3467 	 * @param array $args Method parameters.
       
  3468 	 * @return int
       
  3469 	 */
       
  3470 	function blogger_newPost($args) {
       
  3471 
       
  3472 		$this->escape($args);
       
  3473 
       
  3474 		$blog_ID    = (int) $args[1]; /* though we don't use it yet */
       
  3475 		$username = $args[2];
       
  3476 		$password  = $args[3];
       
  3477 		$content    = $args[4];
       
  3478 		$publish    = $args[5];
       
  3479 
       
  3480 		if ( !$user = $this->login($username, $password) )
       
  3481 			return $this->error;
       
  3482 
       
  3483 		do_action('xmlrpc_call', 'blogger.newPost');
       
  3484 
       
  3485 		$cap = ($publish) ? 'publish_posts' : 'edit_posts';
       
  3486 		if ( !current_user_can($cap) )
       
  3487 			return new IXR_Error(401, __('Sorry, you are not allowed to post on this site.'));
       
  3488 
       
  3489 		$post_status = ($publish) ? 'publish' : 'draft';
       
  3490 
       
  3491 		$post_author = $user->ID;
       
  3492 
       
  3493 		$post_title = xmlrpc_getposttitle($content);
       
  3494 		$post_category = xmlrpc_getpostcategory($content);
       
  3495 		$post_content = xmlrpc_removepostdata($content);
       
  3496 
       
  3497 		$post_date = current_time('mysql');
       
  3498 		$post_date_gmt = current_time('mysql', 1);
       
  3499 
       
  3500 		$post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status');
       
  3501 
       
  3502 		$post_ID = wp_insert_post($post_data);
       
  3503 		if ( is_wp_error( $post_ID ) )
       
  3504 			return new IXR_Error(500, $post_ID->get_error_message());
       
  3505 
       
  3506 		if ( !$post_ID )
       
  3507 			return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
       
  3508 
       
  3509 		$this->attach_uploads( $post_ID, $post_content );
       
  3510 
       
  3511 		do_action( 'xmlrpc_call_success_blogger_newPost', $post_ID, $args );
       
  3512 
       
  3513 		return $post_ID;
       
  3514 	}
       
  3515 
       
  3516 	/**
       
  3517 	 * Edit a post.
       
  3518 	 *
       
  3519 	 * @since 1.5.0
       
  3520 	 *
       
  3521 	 * @param array $args Method parameters.
       
  3522 	 * @return bool true when done.
       
  3523 	 */
       
  3524 	function blogger_editPost($args) {
       
  3525 
       
  3526 		$this->escape($args);
       
  3527 
       
  3528 		$post_ID     = (int) $args[1];
       
  3529 		$username  = $args[2];
       
  3530 		$password   = $args[3];
       
  3531 		$content     = $args[4];
       
  3532 		$publish     = $args[5];
       
  3533 
       
  3534 		if ( !$user = $this->login($username, $password) )
       
  3535 			return $this->error;
       
  3536 
       
  3537 		do_action('xmlrpc_call', 'blogger.editPost');
       
  3538 
       
  3539 		$actual_post = wp_get_single_post($post_ID,ARRAY_A);
       
  3540 
       
  3541 		if ( !$actual_post || $actual_post['post_type'] != 'post' )
       
  3542 			return new IXR_Error(404, __('Sorry, no such post.'));
       
  3543 
       
  3544 		$this->escape($actual_post);
       
  3545 
       
  3546 		if ( !current_user_can('edit_post', $post_ID) )
       
  3547 			return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.'));
       
  3548 
       
  3549 		extract($actual_post, EXTR_SKIP);
       
  3550 
       
  3551 		if ( ('publish' == $post_status) && !current_user_can('publish_posts') )
       
  3552 			return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
       
  3553 
       
  3554 		$post_title = xmlrpc_getposttitle($content);
       
  3555 		$post_category = xmlrpc_getpostcategory($content);
       
  3556 		$post_content = xmlrpc_removepostdata($content);
       
  3557 
       
  3558 		$postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
       
  3559 
       
  3560 		$result = wp_update_post($postdata);
       
  3561 
       
  3562 		if ( !$result )
       
  3563 			return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.'));
       
  3564 
       
  3565 		$this->attach_uploads( $ID, $post_content );
       
  3566 
       
  3567 		do_action( 'xmlrpc_call_success_blogger_editPost', $post_ID, $args );
       
  3568 
       
  3569 		return true;
       
  3570 	}
       
  3571 
       
  3572 	/**
       
  3573 	 * Remove a post.
       
  3574 	 *
       
  3575 	 * @since 1.5.0
       
  3576 	 *
       
  3577 	 * @param array $args Method parameters.
       
  3578 	 * @return bool True when post is deleted.
       
  3579 	 */
       
  3580 	function blogger_deletePost($args) {
       
  3581 		$this->escape($args);
       
  3582 
       
  3583 		$post_ID     = (int) $args[1];
       
  3584 		$username  = $args[2];
       
  3585 		$password   = $args[3];
       
  3586 		$publish     = $args[4];
       
  3587 
       
  3588 		if ( !$user = $this->login($username, $password) )
       
  3589 			return $this->error;
       
  3590 
       
  3591 		do_action('xmlrpc_call', 'blogger.deletePost');
       
  3592 
       
  3593 		$actual_post = wp_get_single_post($post_ID,ARRAY_A);
       
  3594 
       
  3595 		if ( !$actual_post || $actual_post['post_type'] != 'post' )
       
  3596 			return new IXR_Error(404, __('Sorry, no such post.'));
       
  3597 
       
  3598 		if ( !current_user_can('delete_post', $post_ID) )
       
  3599 			return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.'));
       
  3600 
       
  3601 		$result = wp_delete_post($post_ID);
       
  3602 
       
  3603 		if ( !$result )
       
  3604 			return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.'));
       
  3605 
       
  3606 		do_action( 'xmlrpc_call_success_blogger_deletePost', $post_ID, $args );
       
  3607 
       
  3608 		return true;
       
  3609 	}
       
  3610 
       
  3611 	/* MetaWeblog API functions
       
  3612 	 * specs on wherever Dave Winer wants them to be
       
  3613 	 */
       
  3614 
       
  3615 	/**
       
  3616 	 * Create a new post.
       
  3617 	 *
       
  3618 	 * The 'content_struct' argument must contain:
       
  3619 	 *  - title
       
  3620 	 *  - description
       
  3621 	 *  - mt_excerpt
       
  3622 	 *  - mt_text_more
       
  3623 	 *  - mt_keywords
       
  3624 	 *  - mt_tb_ping_urls
       
  3625 	 *  - categories
       
  3626 	 *
       
  3627 	 * Also, it can optionally contain:
       
  3628 	 *  - wp_slug
       
  3629 	 *  - wp_password
       
  3630 	 *  - wp_page_parent_id
       
  3631 	 *  - wp_page_order
       
  3632 	 *  - wp_author_id
       
  3633 	 *  - post_status | page_status - can be 'draft', 'private', 'publish', or 'pending'
       
  3634 	 *  - mt_allow_comments - can be 'open' or 'closed'
       
  3635 	 *  - mt_allow_pings - can be 'open' or 'closed'
       
  3636 	 *  - date_created_gmt
       
  3637 	 *  - dateCreated
       
  3638 	 *  - wp_post_thumbnail
       
  3639 	 *
       
  3640 	 * @since 1.5.0
       
  3641 	 *
       
  3642 	 * @param array $args Method parameters. Contains:
       
  3643 	 *  - blog_id
       
  3644 	 *  - username
       
  3645 	 *  - password
       
  3646 	 *  - content_struct
       
  3647 	 *  - publish
       
  3648 	 * @return int
       
  3649 	 */
       
  3650 	function mw_newPost($args) {
       
  3651 		$this->escape($args);
       
  3652 
       
  3653 		$blog_ID     = (int) $args[0];
       
  3654 		$username  = $args[1];
       
  3655 		$password   = $args[2];
       
  3656 		$content_struct = $args[3];
       
  3657 		$publish     = isset( $args[4] ) ? $args[4] : 0;
       
  3658 
       
  3659 		if ( !$user = $this->login($username, $password) )
       
  3660 			return $this->error;
       
  3661 
       
  3662 		do_action('xmlrpc_call', 'metaWeblog.newPost');
       
  3663 
       
  3664 		$page_template = '';
       
  3665 		if ( !empty( $content_struct['post_type'] ) ) {
       
  3666 			if ( $content_struct['post_type'] == 'page' ) {
       
  3667 				if ( $publish )
       
  3668 					$cap  = 'publish_pages';
       
  3669 				elseif ( isset( $content_struct['page_status'] ) && 'publish' == $content_struct['page_status'] )
       
  3670 					$cap  = 'publish_pages';
       
  3671 				else
       
  3672 					$cap = 'edit_pages';
       
  3673 				$error_message = __( 'Sorry, you are not allowed to publish pages on this site.' );
       
  3674 				$post_type = 'page';
       
  3675 				if ( !empty( $content_struct['wp_page_template'] ) )
       
  3676 					$page_template = $content_struct['wp_page_template'];
       
  3677 			} elseif ( $content_struct['post_type'] == 'post' ) {
       
  3678 				if ( $publish )
       
  3679 					$cap  = 'publish_posts';
       
  3680 				elseif ( isset( $content_struct['post_status'] ) && 'publish' == $content_struct['post_status'] )
       
  3681 					$cap  = 'publish_posts';
       
  3682 				else
       
  3683 					$cap = 'edit_posts';
       
  3684 				$error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
       
  3685 				$post_type = 'post';
       
  3686 			} else {
       
  3687 				// No other post_type values are allowed here
       
  3688 				return new IXR_Error( 401, __( 'Invalid post type' ) );
       
  3689 			}
       
  3690 		} else {
       
  3691 			if ( $publish )
       
  3692 				$cap  = 'publish_posts';
       
  3693 			elseif ( isset( $content_struct['post_status'] ) && 'publish' == $content_struct['post_status'])
       
  3694 				$cap  = 'publish_posts';
       
  3695 			else
       
  3696 				$cap = 'edit_posts';
       
  3697 			$error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
       
  3698 			$post_type = 'post';
       
  3699 		}
       
  3700 
       
  3701 		if ( !current_user_can( $cap ) )
       
  3702 			return new IXR_Error( 401, $error_message );
       
  3703 
       
  3704 		// Check for a valid post format if one was given
       
  3705 		if ( isset( $content_struct['wp_post_format'] ) ) {
       
  3706 			$content_struct['wp_post_format'] = sanitize_key( $content_struct['wp_post_format'] );
       
  3707 			if ( !array_key_exists( $content_struct['wp_post_format'], get_post_format_strings() ) ) {
       
  3708 				return new IXR_Error( 404, __( 'Invalid post format' ) );
       
  3709 			}
       
  3710 		}
       
  3711 
       
  3712 		// Let WordPress generate the post_name (slug) unless
       
  3713 		// one has been provided.
       
  3714 		$post_name = "";
       
  3715 		if ( isset($content_struct['wp_slug']) )
       
  3716 			$post_name = $content_struct['wp_slug'];
       
  3717 
       
  3718 		// Only use a password if one was given.
       
  3719 		if ( isset($content_struct['wp_password']) )
       
  3720 			$post_password = $content_struct['wp_password'];
       
  3721 
       
  3722 		// Only set a post parent if one was provided.
       
  3723 		if ( isset($content_struct['wp_page_parent_id']) )
       
  3724 			$post_parent = $content_struct['wp_page_parent_id'];
       
  3725 
       
  3726 		// Only set the menu_order if it was provided.
       
  3727 		if ( isset($content_struct['wp_page_order']) )
       
  3728 			$menu_order = $content_struct['wp_page_order'];
       
  3729 
       
  3730 		$post_author = $user->ID;
       
  3731 
       
  3732 		// If an author id was provided then use it instead.
       
  3733 		if ( isset($content_struct['wp_author_id']) && ($user->ID != $content_struct['wp_author_id']) ) {
       
  3734 			switch ( $post_type ) {
       
  3735 				case "post":
       
  3736 					if ( !current_user_can('edit_others_posts') )
       
  3737 						return(new IXR_Error(401, __('You are not allowed to post as this user')));
       
  3738 					break;
       
  3739 				case "page":
       
  3740 					if ( !current_user_can('edit_others_pages') )
       
  3741 						return(new IXR_Error(401, __('You are not allowed to create pages as this user')));
       
  3742 					break;
       
  3743 				default:
       
  3744 					return(new IXR_Error(401, __('Invalid post type')));
       
  3745 					break;
       
  3746 			}
       
  3747 			$author = get_userdata( $content_struct['wp_author_id'] );
       
  3748 			if ( ! $author )
       
  3749 				return new IXR_Error( 404, __( 'Invalid author ID.' ) );
       
  3750 			$post_author = $content_struct['wp_author_id'];
       
  3751 		}
       
  3752 
       
  3753 		$post_title = isset( $content_struct['title'] ) ? $content_struct['title'] : null;
       
  3754 		$post_content = isset( $content_struct['description'] ) ? $content_struct['description'] : null;
       
  3755 
       
  3756 		$post_status = $publish ? 'publish' : 'draft';
       
  3757 
       
  3758 		if ( isset( $content_struct["{$post_type}_status"] ) ) {
       
  3759 			switch ( $content_struct["{$post_type}_status"] ) {
       
  3760 				case 'draft':
       
  3761 				case 'pending':
       
  3762 				case 'private':
       
  3763 				case 'publish':
       
  3764 					$post_status = $content_struct["{$post_type}_status"];
       
  3765 					break;
       
  3766 				default:
       
  3767 					$post_status = $publish ? 'publish' : 'draft';
       
  3768 					break;
       
  3769 			}
       
  3770 		}
       
  3771 
       
  3772 		$post_excerpt = isset($content_struct['mt_excerpt']) ? $content_struct['mt_excerpt'] : null;
       
  3773 		$post_more = isset($content_struct['mt_text_more']) ? $content_struct['mt_text_more'] : null;
       
  3774 
       
  3775 		$tags_input = isset($content_struct['mt_keywords']) ? $content_struct['mt_keywords'] : null;
       
  3776 
       
  3777 		if ( isset($content_struct['mt_allow_comments']) ) {
       
  3778 			if ( !is_numeric($content_struct['mt_allow_comments']) ) {
       
  3779 				switch ( $content_struct['mt_allow_comments'] ) {
       
  3780 					case 'closed':
       
  3781 						$comment_status = 'closed';
       
  3782 						break;
       
  3783 					case 'open':
       
  3784 						$comment_status = 'open';
       
  3785 						break;
       
  3786 					default:
       
  3787 						$comment_status = get_option('default_comment_status');
       
  3788 						break;
       
  3789 				}
       
  3790 			} else {
       
  3791 				switch ( (int) $content_struct['mt_allow_comments'] ) {
       
  3792 					case 0:
       
  3793 					case 2:
       
  3794 						$comment_status = 'closed';
       
  3795 						break;
       
  3796 					case 1:
       
  3797 						$comment_status = 'open';
       
  3798 						break;
       
  3799 					default:
       
  3800 						$comment_status = get_option('default_comment_status');
       
  3801 						break;
       
  3802 				}
       
  3803 			}
       
  3804 		} else {
       
  3805 			$comment_status = get_option('default_comment_status');
       
  3806 		}
       
  3807 
       
  3808 		if ( isset($content_struct['mt_allow_pings']) ) {
       
  3809 			if ( !is_numeric($content_struct['mt_allow_pings']) ) {
       
  3810 				switch ( $content_struct['mt_allow_pings'] ) {
       
  3811 					case 'closed':
       
  3812 						$ping_status = 'closed';
       
  3813 						break;
       
  3814 					case 'open':
       
  3815 						$ping_status = 'open';
       
  3816 						break;
       
  3817 					default:
       
  3818 						$ping_status = get_option('default_ping_status');
       
  3819 						break;
       
  3820 				}
       
  3821 			} else {
       
  3822 				switch ( (int) $content_struct['mt_allow_pings'] ) {
       
  3823 					case 0:
       
  3824 						$ping_status = 'closed';
       
  3825 						break;
       
  3826 					case 1:
       
  3827 						$ping_status = 'open';
       
  3828 						break;
       
  3829 					default:
       
  3830 						$ping_status = get_option('default_ping_status');
       
  3831 						break;
       
  3832 				}
       
  3833 			}
       
  3834 		} else {
       
  3835 			$ping_status = get_option('default_ping_status');
       
  3836 		}
       
  3837 
       
  3838 		if ( $post_more )
       
  3839 			$post_content = $post_content . '<!--more-->' . $post_more;
       
  3840 
       
  3841 		$to_ping = null;
       
  3842 		if ( isset( $content_struct['mt_tb_ping_urls'] ) ) {
       
  3843 			$to_ping = $content_struct['mt_tb_ping_urls'];
       
  3844 			if ( is_array($to_ping) )
       
  3845 				$to_ping = implode(' ', $to_ping);
       
  3846 		}
       
  3847 
       
  3848 		// Do some timestamp voodoo
       
  3849 		if ( !empty( $content_struct['date_created_gmt'] ) )
       
  3850 			// We know this is supposed to be GMT, so we're going to slap that Z on there by force
       
  3851 			$dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z';
       
  3852 		elseif ( !empty( $content_struct['dateCreated']) )
       
  3853 			$dateCreated = $content_struct['dateCreated']->getIso();
       
  3854 
       
  3855 		if ( !empty( $dateCreated ) ) {
       
  3856 			$post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
       
  3857 			$post_date_gmt = iso8601_to_datetime($dateCreated, 'GMT');
       
  3858 		} else {
       
  3859 			$post_date = current_time('mysql');
       
  3860 			$post_date_gmt = current_time('mysql', 1);
       
  3861 		}
       
  3862 
       
  3863 		$post_category = array();
       
  3864 		if ( isset( $content_struct['categories'] ) ) {
       
  3865 			$catnames = $content_struct['categories'];
       
  3866 
       
  3867 			if ( is_array($catnames) ) {
       
  3868 				foreach ($catnames as $cat) {
       
  3869 					$post_category[] = get_cat_ID($cat);
       
  3870 				}
       
  3871 			}
       
  3872 		}
       
  3873 
       
  3874 		$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');
       
  3875 
       
  3876 		$post_ID = $postdata['ID'] = get_default_post_to_edit( $post_type, true )->ID;
       
  3877 
       
  3878 		// Only posts can be sticky
       
  3879 		if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
       
  3880 			if ( $content_struct['sticky'] == true )
       
  3881 				stick_post( $post_ID );
       
  3882 			elseif ( $content_struct['sticky'] == false )
       
  3883 				unstick_post( $post_ID );
       
  3884 		}
       
  3885 
       
  3886 		if ( isset($content_struct['custom_fields']) )
       
  3887 			$this->set_custom_fields($post_ID, $content_struct['custom_fields']);
       
  3888 
       
  3889 		if ( isset ( $content_struct['wp_post_thumbnail'] ) ) {
       
  3890 			if ( set_post_thumbnail( $post_ID, $content_struct['wp_post_thumbnail'] ) === false )
       
  3891 				return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
       
  3892 
       
  3893 			unset( $content_struct['wp_post_thumbnail'] );
       
  3894 		}
       
  3895 
       
  3896 		// Handle enclosures
       
  3897 		$thisEnclosure = isset($content_struct['enclosure']) ? $content_struct['enclosure'] : null;
       
  3898 		$this->add_enclosure_if_new($post_ID, $thisEnclosure);
       
  3899 
       
  3900 		$this->attach_uploads( $post_ID, $post_content );
       
  3901 
       
  3902 		// Handle post formats if assigned, value is validated earlier
       
  3903 		// in this function
       
  3904 		if ( isset( $content_struct['wp_post_format'] ) )
       
  3905 			wp_set_post_terms( $post_ID, array( 'post-format-' . $content_struct['wp_post_format'] ), 'post_format' );
       
  3906 
       
  3907 		$post_ID = wp_insert_post( $postdata, true );
       
  3908 		if ( is_wp_error( $post_ID ) )
       
  3909 			return new IXR_Error(500, $post_ID->get_error_message());
       
  3910 
       
  3911 		if ( !$post_ID )
       
  3912 			return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
       
  3913 
       
  3914 		do_action( 'xmlrpc_call_success_mw_newPost', $post_ID, $args );
       
  3915 
       
  3916 		return strval($post_ID);
       
  3917 	}
       
  3918 
       
  3919 	function add_enclosure_if_new($post_ID, $enclosure) {
       
  3920 		if ( is_array( $enclosure ) && isset( $enclosure['url'] ) && isset( $enclosure['length'] ) && isset( $enclosure['type'] ) ) {
       
  3921 
       
  3922 			$encstring = $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type'];
       
  3923 			$found = false;
       
  3924 			foreach ( (array) get_post_custom($post_ID) as $key => $val) {
       
  3925 				if ($key == 'enclosure') {
       
  3926 					foreach ( (array) $val as $enc ) {
       
  3927 						if ($enc == $encstring) {
       
  3928 							$found = true;
       
  3929 							break 2;
       
  3930 						}
       
  3931 					}
       
  3932 				}
       
  3933 			}
       
  3934 			if (!$found)
       
  3935 				add_post_meta( $post_ID, 'enclosure', $encstring );
       
  3936 		}
       
  3937 	}
       
  3938 
       
  3939 	/**
       
  3940 	 * Attach upload to a post.
       
  3941 	 *
       
  3942 	 * @since 2.1.0
       
  3943 	 *
       
  3944 	 * @param int $post_ID Post ID.
       
  3945 	 * @param string $post_content Post Content for attachment.
       
  3946 	 */
       
  3947 	function attach_uploads( $post_ID, $post_content ) {
       
  3948 		global $wpdb;
       
  3949 
       
  3950 		// find any unattached files
       
  3951 		$attachments = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts} WHERE post_parent = '0' AND post_type = 'attachment'" );
       
  3952 		if ( is_array( $attachments ) ) {
       
  3953 			foreach ( $attachments as $file ) {
       
  3954 				if ( strpos( $post_content, $file->guid ) !== false )
       
  3955 					$wpdb->update($wpdb->posts, array('post_parent' => $post_ID), array('ID' => $file->ID) );
       
  3956 			}
       
  3957 		}
       
  3958 	}
       
  3959 
       
  3960 	/**
       
  3961 	 * Edit a post.
       
  3962 	 *
       
  3963 	 * @since 1.5.0
       
  3964 	 *
       
  3965 	 * @param array $args Method parameters.
       
  3966 	 * @return bool True on success.
       
  3967 	 */
       
  3968 	function mw_editPost($args) {
       
  3969 
       
  3970 		$this->escape($args);
       
  3971 
       
  3972 		$post_ID        = (int) $args[0];
       
  3973 		$username       = $args[1];
       
  3974 		$password       = $args[2];
       
  3975 		$content_struct = $args[3];
       
  3976 		$publish        = isset( $args[4] ) ? $args[4] : 0;
       
  3977 
       
  3978 		if ( ! $user = $this->login($username, $password) )
       
  3979 			return $this->error;
       
  3980 
       
  3981 		do_action('xmlrpc_call', 'metaWeblog.editPost');
       
  3982 
       
  3983 		$postdata = wp_get_single_post( $post_ID, ARRAY_A );
       
  3984 
       
  3985 		// If there is no post data for the give post id, stop
       
  3986 		// now and return an error. Other wise a new post will be
       
  3987 		// created (which was the old behavior).
       
  3988 		if ( ! $postdata || empty( $postdata[ 'ID' ] ) )
       
  3989 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  3990 
       
  3991 		if ( ! current_user_can( 'edit_post', $post_ID ) )
       
  3992 			return new IXR_Error( 401, __( 'Sorry, you do not have the right to edit this post.' ) );
       
  3993 
       
  3994 		// Use wp.editPost to edit post types other than post and page.
       
  3995 		if ( ! in_array( $postdata[ 'post_type' ], array( 'post', 'page' ) ) )
       
  3996 			return new IXR_Error( 401, __( 'Invalid post type' ) );
       
  3997 
       
  3998 		// Thwart attempt to change the post type.
       
  3999 		if ( ! empty( $content_struct[ 'post_type' ] ) && ( $content_struct['post_type'] != $postdata[ 'post_type' ] ) )
       
  4000 			return new IXR_Error( 401, __( 'The post type may not be changed.' ) );
       
  4001 
       
  4002 		// Check for a valid post format if one was given
       
  4003 		if ( isset( $content_struct['wp_post_format'] ) ) {
       
  4004 			$content_struct['wp_post_format'] = sanitize_key( $content_struct['wp_post_format'] );
       
  4005 			if ( !array_key_exists( $content_struct['wp_post_format'], get_post_format_strings() ) ) {
       
  4006 				return new IXR_Error( 404, __( 'Invalid post format' ) );
       
  4007 			}
       
  4008 		}
       
  4009 
       
  4010 		$this->escape($postdata);
       
  4011 		extract($postdata, EXTR_SKIP);
       
  4012 
       
  4013 		// Let WordPress manage slug if none was provided.
       
  4014 		$post_name = "";
       
  4015 		$post_name = $postdata['post_name'];
       
  4016 		if ( isset($content_struct['wp_slug']) )
       
  4017 			$post_name = $content_struct['wp_slug'];
       
  4018 
       
  4019 		// Only use a password if one was given.
       
  4020 		if ( isset($content_struct['wp_password']) )
       
  4021 			$post_password = $content_struct['wp_password'];
       
  4022 
       
  4023 		// Only set a post parent if one was given.
       
  4024 		if ( isset($content_struct['wp_page_parent_id']) )
       
  4025 			$post_parent = $content_struct['wp_page_parent_id'];
       
  4026 
       
  4027 		// Only set the menu_order if it was given.
       
  4028 		if ( isset($content_struct['wp_page_order']) )
       
  4029 			$menu_order = $content_struct['wp_page_order'];
       
  4030 
       
  4031 		if ( ! empty( $content_struct['wp_page_template'] ) && 'page' == $post_type )
       
  4032 			$page_template = $content_struct['wp_page_template'];
       
  4033 
       
  4034 		$post_author = $postdata['post_author'];
       
  4035 
       
  4036 		// Only set the post_author if one is set.
       
  4037 		if ( isset($content_struct['wp_author_id']) && ($user->ID != $content_struct['wp_author_id']) ) {
       
  4038 			switch ( $post_type ) {
       
  4039 				case 'post':
       
  4040 					if ( !current_user_can('edit_others_posts') )
       
  4041 						return(new IXR_Error(401, __('You are not allowed to change the post author as this user.')));
       
  4042 					break;
       
  4043 				case 'page':
       
  4044 					if ( !current_user_can('edit_others_pages') )
       
  4045 						return(new IXR_Error(401, __('You are not allowed to change the page author as this user.')));
       
  4046 					break;
       
  4047 				default:
       
  4048 					return(new IXR_Error(401, __('Invalid post type')));
       
  4049 					break;
       
  4050 			}
       
  4051 			$post_author = $content_struct['wp_author_id'];
       
  4052 		}
       
  4053 
       
  4054 		if ( isset($content_struct['mt_allow_comments']) ) {
       
  4055 			if ( !is_numeric($content_struct['mt_allow_comments']) ) {
       
  4056 				switch ( $content_struct['mt_allow_comments'] ) {
       
  4057 					case 'closed':
       
  4058 						$comment_status = 'closed';
       
  4059 						break;
       
  4060 					case 'open':
       
  4061 						$comment_status = 'open';
       
  4062 						break;
       
  4063 					default:
       
  4064 						$comment_status = get_option('default_comment_status');
       
  4065 						break;
       
  4066 				}
       
  4067 			} else {
       
  4068 				switch ( (int) $content_struct['mt_allow_comments'] ) {
       
  4069 					case 0:
       
  4070 					case 2:
       
  4071 						$comment_status = 'closed';
       
  4072 						break;
       
  4073 					case 1:
       
  4074 						$comment_status = 'open';
       
  4075 						break;
       
  4076 					default:
       
  4077 						$comment_status = get_option('default_comment_status');
       
  4078 						break;
       
  4079 				}
       
  4080 			}
       
  4081 		}
       
  4082 
       
  4083 		if ( isset($content_struct['mt_allow_pings']) ) {
       
  4084 			if ( !is_numeric($content_struct['mt_allow_pings']) ) {
       
  4085 				switch ( $content_struct['mt_allow_pings'] ) {
       
  4086 					case 'closed':
       
  4087 						$ping_status = 'closed';
       
  4088 						break;
       
  4089 					case 'open':
       
  4090 						$ping_status = 'open';
       
  4091 						break;
       
  4092 					default:
       
  4093 						$ping_status = get_option('default_ping_status');
       
  4094 						break;
       
  4095 				}
       
  4096 			} else {
       
  4097 				switch ( (int) $content_struct["mt_allow_pings"] ) {
       
  4098 					case 0:
       
  4099 						$ping_status = 'closed';
       
  4100 						break;
       
  4101 					case 1:
       
  4102 						$ping_status = 'open';
       
  4103 						break;
       
  4104 					default:
       
  4105 						$ping_status = get_option('default_ping_status');
       
  4106 						break;
       
  4107 				}
       
  4108 			}
       
  4109 		}
       
  4110 
       
  4111 		if ( isset( $content_struct['title'] ) )
       
  4112 			$post_title =  $content_struct['title'];
       
  4113 
       
  4114 		if ( isset( $content_struct['description'] ) )
       
  4115 			$post_content = $content_struct['description'];
       
  4116 
       
  4117 		$post_category = array();
       
  4118 		if ( isset( $content_struct['categories'] ) ) {
       
  4119 			$catnames = $content_struct['categories'];
       
  4120 			if ( is_array($catnames) ) {
       
  4121 				foreach ($catnames as $cat) {
       
  4122 					$post_category[] = get_cat_ID($cat);
       
  4123 				}
       
  4124 			}
       
  4125 		}
       
  4126 
       
  4127 		if ( isset( $content_struct['mt_excerpt'] ) )
       
  4128 			$post_excerpt =  $content_struct['mt_excerpt'];
       
  4129 
       
  4130 		$post_more = isset( $content_struct['mt_text_more'] ) ? $content_struct['mt_text_more'] : null;
       
  4131 
       
  4132 		$post_status = $publish ? 'publish' : 'draft';
       
  4133 		if ( isset( $content_struct["{$post_type}_status"] ) ) {
       
  4134 			switch( $content_struct["{$post_type}_status"] ) {
       
  4135 				case 'draft':
       
  4136 				case 'pending':
       
  4137 				case 'private':
       
  4138 				case 'publish':
       
  4139 					$post_status = $content_struct["{$post_type}_status"];
       
  4140 					break;
       
  4141 				default:
       
  4142 					$post_status = $publish ? 'publish' : 'draft';
       
  4143 					break;
       
  4144 			}
       
  4145 		}
       
  4146 
       
  4147 		$tags_input = isset( $content_struct['mt_keywords'] ) ? $content_struct['mt_keywords'] : null;
       
  4148 
       
  4149 		if ( ('publish' == $post_status) ) {
       
  4150 			if ( ( 'page' == $post_type ) && !current_user_can('publish_pages') )
       
  4151 				return new IXR_Error(401, __('Sorry, you do not have the right to publish this page.'));
       
  4152 			else if ( !current_user_can('publish_posts') )
       
  4153 				return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
       
  4154 		}
       
  4155 
       
  4156 		if ( $post_more )
       
  4157 			$post_content = $post_content . "<!--more-->" . $post_more;
       
  4158 
       
  4159 		$to_ping = null;
       
  4160 		if ( isset( $content_struct['mt_tb_ping_urls'] ) ) {
       
  4161 			$to_ping = $content_struct['mt_tb_ping_urls'];
       
  4162 			if ( is_array($to_ping) )
       
  4163 				$to_ping = implode(' ', $to_ping);
       
  4164 		}
       
  4165 
       
  4166 		// Do some timestamp voodoo
       
  4167 		if ( !empty( $content_struct['date_created_gmt'] ) )
       
  4168 			// We know this is supposed to be GMT, so we're going to slap that Z on there by force
       
  4169 			$dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z';
       
  4170 		elseif ( !empty( $content_struct['dateCreated']) )
       
  4171 			$dateCreated = $content_struct['dateCreated']->getIso();
       
  4172 
       
  4173 		if ( !empty( $dateCreated ) ) {
       
  4174 			$post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
       
  4175 			$post_date_gmt = iso8601_to_datetime($dateCreated, 'GMT');
       
  4176 		} else {
       
  4177 			$post_date     = $postdata['post_date'];
       
  4178 			$post_date_gmt = $postdata['post_date_gmt'];
       
  4179 		}
       
  4180 
       
  4181 		// We've got all the data -- post it:
       
  4182 		$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');
       
  4183 
       
  4184 		$result = wp_update_post($newpost, true);
       
  4185 		if ( is_wp_error( $result ) )
       
  4186 			return new IXR_Error(500, $result->get_error_message());
       
  4187 
       
  4188 		if ( !$result )
       
  4189 			return new IXR_Error(500, __('Sorry, your entry could not be edited. Something wrong happened.'));
       
  4190 
       
  4191 		// Only posts can be sticky
       
  4192 		if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
       
  4193 			if ( $content_struct['sticky'] == true )
       
  4194 				stick_post( $post_ID );
       
  4195 			elseif ( $content_struct['sticky'] == false )
       
  4196 				unstick_post( $post_ID );
       
  4197 		}
       
  4198 
       
  4199 		if ( isset($content_struct['custom_fields']) )
       
  4200 			$this->set_custom_fields($post_ID, $content_struct['custom_fields']);
       
  4201 
       
  4202 		if ( isset ( $content_struct['wp_post_thumbnail'] ) ) {
       
  4203 			// empty value deletes, non-empty value adds/updates
       
  4204 			if ( empty( $content_struct['wp_post_thumbnail'] ) ) {
       
  4205 				delete_post_thumbnail( $post_ID );
       
  4206 			} else {
       
  4207 				if ( set_post_thumbnail( $post_ID, $content_struct['wp_post_thumbnail'] ) === false )
       
  4208 					return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
       
  4209 			}
       
  4210 			unset( $content_struct['wp_post_thumbnail'] );
       
  4211 		}
       
  4212 
       
  4213 		// Handle enclosures
       
  4214 		$thisEnclosure = isset($content_struct['enclosure']) ? $content_struct['enclosure'] : null;
       
  4215 		$this->add_enclosure_if_new($post_ID, $thisEnclosure);
       
  4216 
       
  4217 		$this->attach_uploads( $ID, $post_content );
       
  4218 
       
  4219 		// Handle post formats if assigned, validation is handled
       
  4220 		// earlier in this function
       
  4221 		if ( isset( $content_struct['wp_post_format'] ) )
       
  4222 			wp_set_post_terms( $post_ID, array( 'post-format-' . $content_struct['wp_post_format'] ), 'post_format' );
       
  4223 
       
  4224 		do_action( 'xmlrpc_call_success_mw_editPost', $post_ID, $args );
       
  4225 
       
  4226 		return true;
       
  4227 	}
       
  4228 
       
  4229 	/**
       
  4230 	 * Retrieve post.
       
  4231 	 *
       
  4232 	 * @since 1.5.0
       
  4233 	 *
       
  4234 	 * @param array $args Method parameters.
       
  4235 	 * @return array
       
  4236 	 */
       
  4237 	function mw_getPost($args) {
       
  4238 
       
  4239 		$this->escape($args);
       
  4240 
       
  4241 		$post_ID     = (int) $args[0];
       
  4242 		$username  = $args[1];
       
  4243 		$password   = $args[2];
       
  4244 
       
  4245 		if ( !$user = $this->login($username, $password) )
       
  4246 			return $this->error;
       
  4247 
       
  4248 		$postdata = wp_get_single_post($post_ID, ARRAY_A);
       
  4249 		if ( ! $postdata )
       
  4250 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  4251 
       
  4252 		if ( !current_user_can( 'edit_post', $post_ID ) )
       
  4253 			return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
       
  4254 
       
  4255 		do_action('xmlrpc_call', 'metaWeblog.getPost');
       
  4256 
       
  4257 		if ($postdata['post_date'] != '') {
       
  4258 			$post_date = $this->_convert_date( $postdata['post_date'] );
       
  4259 			$post_date_gmt = $this->_convert_date_gmt( $postdata['post_date_gmt'],  $postdata['post_date'] );
       
  4260 			$post_modified = $this->_convert_date( $postdata['post_modified'] );
       
  4261 			$post_modified_gmt = $this->_convert_date_gmt( $postdata['post_modified_gmt'], $postdata['post_modified'] );
       
  4262 
       
  4263 			$categories = array();
       
  4264 			$catids = wp_get_post_categories($post_ID);
       
  4265 			foreach($catids as $catid)
       
  4266 				$categories[] = get_cat_name($catid);
       
  4267 
       
  4268 			$tagnames = array();
       
  4269 			$tags = wp_get_post_tags( $post_ID );
       
  4270 			if ( !empty( $tags ) ) {
       
  4271 				foreach ( $tags as $tag )
       
  4272 					$tagnames[] = $tag->name;
       
  4273 				$tagnames = implode( ', ', $tagnames );
       
  4274 			} else {
       
  4275 				$tagnames = '';
       
  4276 			}
       
  4277 
       
  4278 			$post = get_extended($postdata['post_content']);
       
  4279 			$link = post_permalink($postdata['ID']);
       
  4280 
       
  4281 			// Get the author info.
       
  4282 			$author = get_userdata($postdata['post_author']);
       
  4283 
       
  4284 			$allow_comments = ('open' == $postdata['comment_status']) ? 1 : 0;
       
  4285 			$allow_pings = ('open' == $postdata['ping_status']) ? 1 : 0;
       
  4286 
       
  4287 			// Consider future posts as published
       
  4288 			if ( $postdata['post_status'] === 'future' )
       
  4289 				$postdata['post_status'] = 'publish';
       
  4290 
       
  4291 			// Get post format
       
  4292 			$post_format = get_post_format( $post_ID );
       
  4293 			if ( empty( $post_format ) )
       
  4294 				$post_format = 'standard';
       
  4295 
       
  4296 			$sticky = false;
       
  4297 			if ( is_sticky( $post_ID ) )
       
  4298 				$sticky = true;
       
  4299 
       
  4300 			$enclosure = array();
       
  4301 			foreach ( (array) get_post_custom($post_ID) as $key => $val) {
       
  4302 				if ($key == 'enclosure') {
       
  4303 					foreach ( (array) $val as $enc ) {
       
  4304 						$encdata = explode("\n", $enc);
       
  4305 						$enclosure['url'] = trim(htmlspecialchars($encdata[0]));
       
  4306 						$enclosure['length'] = (int) trim($encdata[1]);
       
  4307 						$enclosure['type'] = trim($encdata[2]);
       
  4308 						break 2;
       
  4309 					}
       
  4310 				}
       
  4311 			}
       
  4312 
       
  4313 			$resp = array(
       
  4314 				'dateCreated' => $post_date,
       
  4315 				'userid' => $postdata['post_author'],
       
  4316 				'postid' => $postdata['ID'],
       
  4317 				'description' => $post['main'],
       
  4318 				'title' => $postdata['post_title'],
       
  4319 				'link' => $link,
       
  4320 				'permaLink' => $link,
       
  4321 				// commented out because no other tool seems to use this
       
  4322 				//	      'content' => $entry['post_content'],
       
  4323 				'categories' => $categories,
       
  4324 				'mt_excerpt' => $postdata['post_excerpt'],
       
  4325 				'mt_text_more' => $post['extended'],
       
  4326 				'wp_more_text' => $post['more_text'],
       
  4327 				'mt_allow_comments' => $allow_comments,
       
  4328 				'mt_allow_pings' => $allow_pings,
       
  4329 				'mt_keywords' => $tagnames,
       
  4330 				'wp_slug' => $postdata['post_name'],
       
  4331 				'wp_password' => $postdata['post_password'],
       
  4332 				'wp_author_id' => (string) $author->ID,
       
  4333 				'wp_author_display_name' => $author->display_name,
       
  4334 				'date_created_gmt' => $post_date_gmt,
       
  4335 				'post_status' => $postdata['post_status'],
       
  4336 				'custom_fields' => $this->get_custom_fields($post_ID),
       
  4337 				'wp_post_format' => $post_format,
       
  4338 				'sticky' => $sticky,
       
  4339 				'date_modified' => $post_modified,
       
  4340 				'date_modified_gmt' => $post_modified_gmt
       
  4341 			);
       
  4342 
       
  4343 			if ( !empty($enclosure) ) $resp['enclosure'] = $enclosure;
       
  4344 
       
  4345 			$resp['wp_post_thumbnail'] = get_post_thumbnail_id( $postdata['ID'] );
       
  4346 
       
  4347 			return $resp;
       
  4348 		} else {
       
  4349 			return new IXR_Error(404, __('Sorry, no such post.'));
       
  4350 		}
       
  4351 	}
       
  4352 
       
  4353 	/**
       
  4354 	 * Retrieve list of recent posts.
       
  4355 	 *
       
  4356 	 * @since 1.5.0
       
  4357 	 *
       
  4358 	 * @param array $args Method parameters.
       
  4359 	 * @return array
       
  4360 	 */
       
  4361 	function mw_getRecentPosts($args) {
       
  4362 
       
  4363 		$this->escape($args);
       
  4364 
       
  4365 		$blog_ID     = (int) $args[0];
       
  4366 		$username  = $args[1];
       
  4367 		$password   = $args[2];
       
  4368 		if ( isset( $args[3] ) )
       
  4369 			$query = array( 'numberposts' => absint( $args[3] ) );
       
  4370 		else
       
  4371 			$query = array();
       
  4372 
       
  4373 		if ( !$user = $this->login($username, $password) )
       
  4374 			return $this->error;
       
  4375 
       
  4376 		do_action('xmlrpc_call', 'metaWeblog.getRecentPosts');
       
  4377 
       
  4378 		$posts_list = wp_get_recent_posts( $query );
       
  4379 
       
  4380 		if ( !$posts_list )
       
  4381 			return array();
       
  4382 
       
  4383 		foreach ($posts_list as $entry) {
       
  4384 			if ( !current_user_can( 'edit_post', $entry['ID'] ) )
       
  4385 				continue;
       
  4386 
       
  4387 			$post_date = $this->_convert_date( $entry['post_date'] );
       
  4388 			$post_date_gmt = $this->_convert_date_gmt( $entry['post_date_gmt'], $entry['post_date'] );
       
  4389 			$post_modified = $this->_convert_date( $entry['post_modified'] );
       
  4390 			$post_modified_gmt = $this->_convert_date_gmt( $entry['post_modified_gmt'], $entry['post_modified'] );
       
  4391 
       
  4392 			$categories = array();
       
  4393 			$catids = wp_get_post_categories($entry['ID']);
       
  4394 			foreach( $catids as $catid )
       
  4395 				$categories[] = get_cat_name($catid);
       
  4396 
       
  4397 			$tagnames = array();
       
  4398 			$tags = wp_get_post_tags( $entry['ID'] );
       
  4399 			if ( !empty( $tags ) ) {
       
  4400 				foreach ( $tags as $tag ) {
       
  4401 					$tagnames[] = $tag->name;
       
  4402 				}
       
  4403 				$tagnames = implode( ', ', $tagnames );
       
  4404 			} else {
       
  4405 				$tagnames = '';
       
  4406 			}
       
  4407 
       
  4408 			$post = get_extended($entry['post_content']);
       
  4409 			$link = post_permalink($entry['ID']);
       
  4410 
       
  4411 			// Get the post author info.
       
  4412 			$author = get_userdata($entry['post_author']);
       
  4413 
       
  4414 			$allow_comments = ('open' == $entry['comment_status']) ? 1 : 0;
       
  4415 			$allow_pings = ('open' == $entry['ping_status']) ? 1 : 0;
       
  4416 
       
  4417 			// Consider future posts as published
       
  4418 			if ( $entry['post_status'] === 'future' )
       
  4419 				$entry['post_status'] = 'publish';
       
  4420 
       
  4421 			// Get post format
       
  4422 			$post_format = get_post_format( $entry['ID'] );
       
  4423 			if ( empty( $post_format ) )
       
  4424 				$post_format = 'standard';
       
  4425 
       
  4426 			$struct[] = array(
       
  4427 				'dateCreated' => $post_date,
       
  4428 				'userid' => $entry['post_author'],
       
  4429 				'postid' => (string) $entry['ID'],
       
  4430 				'description' => $post['main'],
       
  4431 				'title' => $entry['post_title'],
       
  4432 				'link' => $link,
       
  4433 				'permaLink' => $link,
       
  4434 				// commented out because no other tool seems to use this
       
  4435 				// 'content' => $entry['post_content'],
       
  4436 				'categories' => $categories,
       
  4437 				'mt_excerpt' => $entry['post_excerpt'],
       
  4438 				'mt_text_more' => $post['extended'],
       
  4439 				'wp_more_text' => $post['more_text'],
       
  4440 				'mt_allow_comments' => $allow_comments,
       
  4441 				'mt_allow_pings' => $allow_pings,
       
  4442 				'mt_keywords' => $tagnames,
       
  4443 				'wp_slug' => $entry['post_name'],
       
  4444 				'wp_password' => $entry['post_password'],
       
  4445 				'wp_author_id' => (string) $author->ID,
       
  4446 				'wp_author_display_name' => $author->display_name,
       
  4447 				'date_created_gmt' => $post_date_gmt,
       
  4448 				'post_status' => $entry['post_status'],
       
  4449 				'custom_fields' => $this->get_custom_fields($entry['ID']),
       
  4450 				'wp_post_format' => $post_format,
       
  4451 				'date_modified' => $post_modified,
       
  4452 				'date_modified_gmt' => $post_modified_gmt
       
  4453 			);
       
  4454 
       
  4455 			$entry_index = count( $struct ) - 1;
       
  4456 			$struct[ $entry_index ][ 'wp_post_thumbnail' ] = get_post_thumbnail_id( $entry['ID'] );
       
  4457 		}
       
  4458 
       
  4459 		$recent_posts = array();
       
  4460 		for ( $j=0; $j<count($struct); $j++ ) {
       
  4461 			array_push($recent_posts, $struct[$j]);
       
  4462 		}
       
  4463 
       
  4464 		return $recent_posts;
       
  4465 	}
       
  4466 
       
  4467 	/**
       
  4468 	 * Retrieve the list of categories on a given blog.
       
  4469 	 *
       
  4470 	 * @since 1.5.0
       
  4471 	 *
       
  4472 	 * @param array $args Method parameters.
       
  4473 	 * @return array
       
  4474 	 */
       
  4475 	function mw_getCategories($args) {
       
  4476 
       
  4477 		$this->escape($args);
       
  4478 
       
  4479 		$blog_ID     = (int) $args[0];
       
  4480 		$username  = $args[1];
       
  4481 		$password   = $args[2];
       
  4482 
       
  4483 		if ( !$user = $this->login($username, $password) )
       
  4484 			return $this->error;
       
  4485 
       
  4486 		if ( !current_user_can( 'edit_posts' ) )
       
  4487 			return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) );
       
  4488 
       
  4489 		do_action('xmlrpc_call', 'metaWeblog.getCategories');
       
  4490 
       
  4491 		$categories_struct = array();
       
  4492 
       
  4493 		if ( $cats = get_categories(array('get' => 'all')) ) {
       
  4494 			foreach ( $cats as $cat ) {
       
  4495 				$struct['categoryId'] = $cat->term_id;
       
  4496 				$struct['parentId'] = $cat->parent;
       
  4497 				$struct['description'] = $cat->name;
       
  4498 				$struct['categoryDescription'] = $cat->description;
       
  4499 				$struct['categoryName'] = $cat->name;
       
  4500 				$struct['htmlUrl'] = esc_html(get_category_link($cat->term_id));
       
  4501 				$struct['rssUrl'] = esc_html(get_category_feed_link($cat->term_id, 'rss2'));
       
  4502 
       
  4503 				$categories_struct[] = $struct;
       
  4504 			}
       
  4505 		}
       
  4506 
       
  4507 		return $categories_struct;
       
  4508 	}
       
  4509 
       
  4510 	/**
       
  4511 	 * Uploads a file, following your settings.
       
  4512 	 *
       
  4513 	 * Adapted from a patch by Johann Richard.
       
  4514 	 *
       
  4515 	 * @link http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/
       
  4516 	 *
       
  4517 	 * @since 1.5.0
       
  4518 	 *
       
  4519 	 * @param array $args Method parameters.
       
  4520 	 * @return array
       
  4521 	 */
       
  4522 	function mw_newMediaObject($args) {
       
  4523 		global $wpdb;
       
  4524 
       
  4525 		$blog_ID     = (int) $args[0];
       
  4526 		$username  = $wpdb->escape($args[1]);
       
  4527 		$password   = $wpdb->escape($args[2]);
       
  4528 		$data        = $args[3];
       
  4529 
       
  4530 		$name = sanitize_file_name( $data['name'] );
       
  4531 		$type = $data['type'];
       
  4532 		$bits = $data['bits'];
       
  4533 
       
  4534 		if ( !$user = $this->login($username, $password) )
       
  4535 			return $this->error;
       
  4536 
       
  4537 		do_action('xmlrpc_call', 'metaWeblog.newMediaObject');
       
  4538 
       
  4539 		if ( !current_user_can('upload_files') ) {
       
  4540 			$this->error = new IXR_Error( 401, __( 'You do not have permission to upload files.' ) );
       
  4541 			return $this->error;
       
  4542 		}
       
  4543 
       
  4544 		if ( $upload_err = apply_filters( 'pre_upload_error', false ) )
       
  4545 			return new IXR_Error(500, $upload_err);
       
  4546 
       
  4547 		if ( !empty($data['overwrite']) && ($data['overwrite'] == true) ) {
       
  4548 			// Get postmeta info on the object.
       
  4549 			$old_file = $wpdb->get_row("
       
  4550 				SELECT ID
       
  4551 				FROM {$wpdb->posts}
       
  4552 				WHERE post_title = '{$name}'
       
  4553 					AND post_type = 'attachment'
       
  4554 			");
       
  4555 
       
  4556 			// Delete previous file.
       
  4557 			wp_delete_attachment($old_file->ID);
       
  4558 
       
  4559 			// Make sure the new name is different by pre-pending the
       
  4560 			// previous post id.
       
  4561 			$filename = preg_replace('/^wpid\d+-/', '', $name);
       
  4562 			$name = "wpid{$old_file->ID}-{$filename}";
       
  4563 		}
       
  4564 
       
  4565 		$upload = wp_upload_bits($name, null, $bits);
       
  4566 		if ( ! empty($upload['error']) ) {
       
  4567 			$errorString = sprintf(__('Could not write file %1$s (%2$s)'), $name, $upload['error']);
       
  4568 			return new IXR_Error(500, $errorString);
       
  4569 		}
       
  4570 		// Construct the attachment array
       
  4571 		// attach to post_id 0
       
  4572 		$post_id = 0;
       
  4573 		$attachment = array(
       
  4574 			'post_title' => $name,
       
  4575 			'post_content' => '',
       
  4576 			'post_type' => 'attachment',
       
  4577 			'post_parent' => $post_id,
       
  4578 			'post_mime_type' => $type,
       
  4579 			'guid' => $upload[ 'url' ]
       
  4580 		);
       
  4581 
       
  4582 		// Save the data
       
  4583 		$id = wp_insert_attachment( $attachment, $upload[ 'file' ], $post_id );
       
  4584 		wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );
       
  4585 
       
  4586 		do_action( 'xmlrpc_call_success_mw_newMediaObject', $id, $args );
       
  4587 
       
  4588 		$struct = array(
       
  4589 			'id'   => strval( $id ),
       
  4590 			'file' => $name,
       
  4591 			'url'  => $upload[ 'url' ],
       
  4592 			'type' => $type
       
  4593 		);
       
  4594 		return apply_filters( 'wp_handle_upload', $struct, 'upload' );
       
  4595 	}
       
  4596 
       
  4597 	/* MovableType API functions
       
  4598 	 * specs on http://www.movabletype.org/docs/mtmanual_programmatic.html
       
  4599 	 */
       
  4600 
       
  4601 	/**
       
  4602 	 * Retrieve the post titles of recent posts.
       
  4603 	 *
       
  4604 	 * @since 1.5.0
       
  4605 	 *
       
  4606 	 * @param array $args Method parameters.
       
  4607 	 * @return array
       
  4608 	 */
       
  4609 	function mt_getRecentPostTitles($args) {
       
  4610 
       
  4611 		$this->escape($args);
       
  4612 
       
  4613 		$blog_ID     = (int) $args[0];
       
  4614 		$username  = $args[1];
       
  4615 		$password   = $args[2];
       
  4616 		if ( isset( $args[3] ) )
       
  4617 			$query = array( 'numberposts' => absint( $args[3] ) );
       
  4618 		else
       
  4619 			$query = array();
       
  4620 
       
  4621 		if ( !$user = $this->login($username, $password) )
       
  4622 			return $this->error;
       
  4623 
       
  4624 		do_action('xmlrpc_call', 'mt.getRecentPostTitles');
       
  4625 
       
  4626 		$posts_list = wp_get_recent_posts( $query );
       
  4627 
       
  4628 		if ( !$posts_list ) {
       
  4629 			$this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
       
  4630 			return $this->error;
       
  4631 		}
       
  4632 
       
  4633 		$struct = array();
       
  4634 
       
  4635 		foreach ($posts_list as $entry) {
       
  4636 			if ( !current_user_can( 'edit_post', $entry['ID'] ) )
       
  4637 				continue;
       
  4638 
       
  4639 			$post_date = $this->_convert_date( $entry['post_date'] );
       
  4640 			$post_date_gmt = $this->_convert_date_gmt( $entry['post_date_gmt'], $entry['post_date'] );
       
  4641 
       
  4642 			$struct[] = array(
       
  4643 				'dateCreated' => $post_date,
       
  4644 				'userid' => $entry['post_author'],
       
  4645 				'postid' => (string) $entry['ID'],
       
  4646 				'title' => $entry['post_title'],
       
  4647 				'post_status' => $entry['post_status'],
       
  4648 				'date_created_gmt' => $post_date_gmt
       
  4649 			);
       
  4650 
       
  4651 		}
       
  4652 
       
  4653 		$recent_posts = array();
       
  4654 		for ( $j=0; $j<count($struct); $j++ ) {
       
  4655 			array_push($recent_posts, $struct[$j]);
       
  4656 		}
       
  4657 
       
  4658 		return $recent_posts;
       
  4659 	}
       
  4660 
       
  4661 	/**
       
  4662 	 * Retrieve list of all categories on blog.
       
  4663 	 *
       
  4664 	 * @since 1.5.0
       
  4665 	 *
       
  4666 	 * @param array $args Method parameters.
       
  4667 	 * @return array
       
  4668 	 */
       
  4669 	function mt_getCategoryList($args) {
       
  4670 
       
  4671 		$this->escape($args);
       
  4672 
       
  4673 		$blog_ID     = (int) $args[0];
       
  4674 		$username  = $args[1];
       
  4675 		$password   = $args[2];
       
  4676 
       
  4677 		if ( !$user = $this->login($username, $password) )
       
  4678 			return $this->error;
       
  4679 
       
  4680 		if ( !current_user_can( 'edit_posts' ) )
       
  4681 			return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) );
       
  4682 
       
  4683 		do_action('xmlrpc_call', 'mt.getCategoryList');
       
  4684 
       
  4685 		$categories_struct = array();
       
  4686 
       
  4687 		if ( $cats = get_categories(array('hide_empty' => 0, 'hierarchical' => 0)) ) {
       
  4688 			foreach ( $cats as $cat ) {
       
  4689 				$struct['categoryId'] = $cat->term_id;
       
  4690 				$struct['categoryName'] = $cat->name;
       
  4691 
       
  4692 				$categories_struct[] = $struct;
       
  4693 			}
       
  4694 		}
       
  4695 
       
  4696 		return $categories_struct;
       
  4697 	}
       
  4698 
       
  4699 	/**
       
  4700 	 * Retrieve post categories.
       
  4701 	 *
       
  4702 	 * @since 1.5.0
       
  4703 	 *
       
  4704 	 * @param array $args Method parameters.
       
  4705 	 * @return array
       
  4706 	 */
       
  4707 	function mt_getPostCategories($args) {
       
  4708 
       
  4709 		$this->escape($args);
       
  4710 
       
  4711 		$post_ID     = (int) $args[0];
       
  4712 		$username  = $args[1];
       
  4713 		$password   = $args[2];
       
  4714 
       
  4715 		if ( !$user = $this->login($username, $password) )
       
  4716 			return $this->error;
       
  4717 
       
  4718 		if ( ! get_post( $post_ID ) )
       
  4719 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  4720 
       
  4721 		if ( !current_user_can( 'edit_post', $post_ID ) )
       
  4722 			return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) );
       
  4723 
       
  4724 		do_action('xmlrpc_call', 'mt.getPostCategories');
       
  4725 
       
  4726 		$categories = array();
       
  4727 		$catids = wp_get_post_categories(intval($post_ID));
       
  4728 		// first listed category will be the primary category
       
  4729 		$isPrimary = true;
       
  4730 		foreach ( $catids as $catid ) {
       
  4731 			$categories[] = array(
       
  4732 				'categoryName' => get_cat_name($catid),
       
  4733 				'categoryId' => (string) $catid,
       
  4734 				'isPrimary' => $isPrimary
       
  4735 			);
       
  4736 			$isPrimary = false;
       
  4737 		}
       
  4738 
       
  4739 		return $categories;
       
  4740 	}
       
  4741 
       
  4742 	/**
       
  4743 	 * Sets categories for a post.
       
  4744 	 *
       
  4745 	 * @since 1.5.0
       
  4746 	 *
       
  4747 	 * @param array $args Method parameters.
       
  4748 	 * @return bool True on success.
       
  4749 	 */
       
  4750 	function mt_setPostCategories($args) {
       
  4751 
       
  4752 		$this->escape($args);
       
  4753 
       
  4754 		$post_ID     = (int) $args[0];
       
  4755 		$username  = $args[1];
       
  4756 		$password   = $args[2];
       
  4757 		$categories  = $args[3];
       
  4758 
       
  4759 		if ( !$user = $this->login($username, $password) )
       
  4760 			return $this->error;
       
  4761 
       
  4762 		do_action('xmlrpc_call', 'mt.setPostCategories');
       
  4763 
       
  4764 		if ( ! get_post( $post_ID ) )
       
  4765 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  4766 
       
  4767 		if ( !current_user_can('edit_post', $post_ID) )
       
  4768 			return new IXR_Error(401, __('Sorry, you cannot edit this post.'));
       
  4769 
       
  4770 		foreach ( $categories as $cat ) {
       
  4771 			$catids[] = $cat['categoryId'];
       
  4772 		}
       
  4773 
       
  4774 		wp_set_post_categories($post_ID, $catids);
       
  4775 
       
  4776 		return true;
       
  4777 	}
       
  4778 
       
  4779 	/**
       
  4780 	 * Retrieve an array of methods supported by this server.
       
  4781 	 *
       
  4782 	 * @since 1.5.0
       
  4783 	 *
       
  4784 	 * @param array $args Method parameters.
       
  4785 	 * @return array
       
  4786 	 */
       
  4787 	function mt_supportedMethods($args) {
       
  4788 
       
  4789 		do_action('xmlrpc_call', 'mt.supportedMethods');
       
  4790 
       
  4791 		$supported_methods = array();
       
  4792 		foreach ( $this->methods as $key => $value ) {
       
  4793 			$supported_methods[] = $key;
       
  4794 		}
       
  4795 
       
  4796 		return $supported_methods;
       
  4797 	}
       
  4798 
       
  4799 	/**
       
  4800 	 * Retrieve an empty array because we don't support per-post text filters.
       
  4801 	 *
       
  4802 	 * @since 1.5.0
       
  4803 	 *
       
  4804 	 * @param array $args Method parameters.
       
  4805 	 */
       
  4806 	function mt_supportedTextFilters($args) {
       
  4807 		do_action('xmlrpc_call', 'mt.supportedTextFilters');
       
  4808 		return apply_filters('xmlrpc_text_filters', array());
       
  4809 	}
       
  4810 
       
  4811 	/**
       
  4812 	 * Retrieve trackbacks sent to a given post.
       
  4813 	 *
       
  4814 	 * @since 1.5.0
       
  4815 	 *
       
  4816 	 * @param array $args Method parameters.
       
  4817 	 * @return mixed
       
  4818 	 */
       
  4819 	function mt_getTrackbackPings($args) {
       
  4820 
       
  4821 		global $wpdb;
       
  4822 
       
  4823 		$post_ID = intval($args);
       
  4824 
       
  4825 		do_action('xmlrpc_call', 'mt.getTrackbackPings');
       
  4826 
       
  4827 		$actual_post = wp_get_single_post($post_ID, ARRAY_A);
       
  4828 
       
  4829 		if ( !$actual_post )
       
  4830 			return new IXR_Error(404, __('Sorry, no such post.'));
       
  4831 
       
  4832 		$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) );
       
  4833 
       
  4834 		if ( !$comments )
       
  4835 			return array();
       
  4836 
       
  4837 		$trackback_pings = array();
       
  4838 		foreach ( $comments as $comment ) {
       
  4839 			if ( 'trackback' == $comment->comment_type ) {
       
  4840 				$content = $comment->comment_content;
       
  4841 				$title = substr($content, 8, (strpos($content, '</strong>') - 8));
       
  4842 				$trackback_pings[] = array(
       
  4843 					'pingTitle' => $title,
       
  4844 					'pingURL'   => $comment->comment_author_url,
       
  4845 					'pingIP'    => $comment->comment_author_IP
       
  4846 				);
       
  4847 			}
       
  4848 		}
       
  4849 
       
  4850 		return $trackback_pings;
       
  4851 	}
       
  4852 
       
  4853 	/**
       
  4854 	 * Sets a post's publish status to 'publish'.
       
  4855 	 *
       
  4856 	 * @since 1.5.0
       
  4857 	 *
       
  4858 	 * @param array $args Method parameters.
       
  4859 	 * @return int
       
  4860 	 */
       
  4861 	function mt_publishPost($args) {
       
  4862 
       
  4863 		$this->escape($args);
       
  4864 
       
  4865 		$post_ID     = (int) $args[0];
       
  4866 		$username  = $args[1];
       
  4867 		$password   = $args[2];
       
  4868 
       
  4869 		if ( !$user = $this->login($username, $password) )
       
  4870 			return $this->error;
       
  4871 
       
  4872 		do_action('xmlrpc_call', 'mt.publishPost');
       
  4873 
       
  4874 		$postdata = wp_get_single_post($post_ID, ARRAY_A);
       
  4875 		if ( ! $postdata )
       
  4876 			return new IXR_Error( 404, __( 'Invalid post ID.' ) );
       
  4877 
       
  4878 		if ( !current_user_can('publish_posts') || !current_user_can('edit_post', $post_ID) )
       
  4879 			return new IXR_Error(401, __('Sorry, you cannot publish this post.'));
       
  4880 
       
  4881 		$postdata['post_status'] = 'publish';
       
  4882 
       
  4883 		// retain old cats
       
  4884 		$cats = wp_get_post_categories($post_ID);
       
  4885 		$postdata['post_category'] = $cats;
       
  4886 		$this->escape($postdata);
       
  4887 
       
  4888 		$result = wp_update_post($postdata);
       
  4889 
       
  4890 		return $result;
       
  4891 	}
       
  4892 
       
  4893 	/* PingBack functions
       
  4894 	 * specs on www.hixie.ch/specs/pingback/pingback
       
  4895 	 */
       
  4896 
       
  4897 	/**
       
  4898 	 * Retrieves a pingback and registers it.
       
  4899 	 *
       
  4900 	 * @since 1.5.0
       
  4901 	 *
       
  4902 	 * @param array $args Method parameters.
       
  4903 	 * @return array
       
  4904 	 */
       
  4905 	function pingback_ping($args) {
       
  4906 		global $wpdb;
       
  4907 
       
  4908 		do_action('xmlrpc_call', 'pingback.ping');
       
  4909 
       
  4910 		$this->escape($args);
       
  4911 
       
  4912 		$pagelinkedfrom = $args[0];
       
  4913 		$pagelinkedto   = $args[1];
       
  4914 
       
  4915 		$title = '';
       
  4916 
       
  4917 		$pagelinkedfrom = str_replace('&amp;', '&', $pagelinkedfrom);
       
  4918 		$pagelinkedto = str_replace('&amp;', '&', $pagelinkedto);
       
  4919 		$pagelinkedto = str_replace('&', '&amp;', $pagelinkedto);
       
  4920 
       
  4921 		// Check if the page linked to is in our site
       
  4922 		$pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home')));
       
  4923 		if ( !$pos1 )
       
  4924 			return new IXR_Error(0, __('Is there no link to us?'));
       
  4925 
       
  4926 		// let's find which post is linked to
       
  4927 		// FIXME: does url_to_postid() cover all these cases already?
       
  4928 		//        if so, then let's use it and drop the old code.
       
  4929 		$urltest = parse_url($pagelinkedto);
       
  4930 		if ( $post_ID = url_to_postid($pagelinkedto) ) {
       
  4931 			$way = 'url_to_postid()';
       
  4932 		} elseif ( preg_match('#p/[0-9]{1,}#', $urltest['path'], $match) ) {
       
  4933 			// the path defines the post_ID (archives/p/XXXX)
       
  4934 			$blah = explode('/', $match[0]);
       
  4935 			$post_ID = (int) $blah[1];
       
  4936 			$way = 'from the path';
       
  4937 		} elseif ( preg_match('#p=[0-9]{1,}#', $urltest['query'], $match) ) {
       
  4938 			// the querystring defines the post_ID (?p=XXXX)
       
  4939 			$blah = explode('=', $match[0]);
       
  4940 			$post_ID = (int) $blah[1];
       
  4941 			$way = 'from the querystring';
       
  4942 		} elseif ( isset($urltest['fragment']) ) {
       
  4943 			// an #anchor is there, it's either...
       
  4944 			if ( intval($urltest['fragment']) ) {
       
  4945 				// ...an integer #XXXX (simplest case)
       
  4946 				$post_ID = (int) $urltest['fragment'];
       
  4947 				$way = 'from the fragment (numeric)';
       
  4948 			} elseif ( preg_match('/post-[0-9]+/',$urltest['fragment']) ) {
       
  4949 				// ...a post id in the form 'post-###'
       
  4950 				$post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']);
       
  4951 				$way = 'from the fragment (post-###)';
       
  4952 			} elseif ( is_string($urltest['fragment']) ) {
       
  4953 				// ...or a string #title, a little more complicated
       
  4954 				$title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']);
       
  4955 				$sql = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title RLIKE %s", like_escape( $title ) );
       
  4956 				if (! ($post_ID = $wpdb->get_var($sql)) ) {
       
  4957 					// returning unknown error '0' is better than die()ing
       
  4958 			  		return new IXR_Error(0, '');
       
  4959 				}
       
  4960 				$way = 'from the fragment (title)';
       
  4961 			}
       
  4962 		} else {
       
  4963 			// TODO: Attempt to extract a post ID from the given URL
       
  4964 	  		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.'));
       
  4965 		}
       
  4966 		$post_ID = (int) $post_ID;
       
  4967 
       
  4968 		$post = get_post($post_ID);
       
  4969 
       
  4970 		if ( !$post ) // Post_ID not found
       
  4971 	  		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.'));
       
  4972 
       
  4973 		if ( $post_ID == url_to_postid($pagelinkedfrom) )
       
  4974 			return new IXR_Error(0, __('The source URL and the target URL cannot both point to the same resource.'));
       
  4975 
       
  4976 		// Check if pings are on
       
  4977 		if ( !pings_open($post) )
       
  4978 	  		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.'));
       
  4979 
       
  4980 		// Let's check that the remote site didn't already pingback this entry
       
  4981 		if ( $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $post_ID, $pagelinkedfrom) ) )
       
  4982 			return new IXR_Error( 48, __( 'The pingback has already been registered.' ) );
       
  4983 
       
  4984 		// very stupid, but gives time to the 'from' server to publish !
       
  4985 		sleep(1);
       
  4986 
       
  4987 		// Let's check the remote site
       
  4988 		$linea = wp_remote_fopen( $pagelinkedfrom );
       
  4989 		if ( !$linea )
       
  4990 	  		return new IXR_Error(16, __('The source URL does not exist.'));
       
  4991 
       
  4992 		$linea = apply_filters('pre_remote_source', $linea, $pagelinkedto);
       
  4993 
       
  4994 		// Work around bug in strip_tags():
       
  4995 		$linea = str_replace('<!DOC', '<DOC', $linea);
       
  4996 		$linea = preg_replace( '/[\s\r\n\t]+/', ' ', $linea ); // normalize spaces
       
  4997 		$linea = preg_replace( "/ <(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $linea );
       
  4998 
       
  4999 		preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle);
       
  5000 		$title = $matchtitle[1];
       
  5001 		if ( empty( $title ) )
       
  5002 			return new IXR_Error(32, __('We cannot find a title on that page.'));
       
  5003 
       
  5004 		$linea = strip_tags( $linea, '<a>' ); // just keep the tag we need
       
  5005 
       
  5006 		$p = explode( "\n\n", $linea );
       
  5007 
       
  5008 		$preg_target = preg_quote($pagelinkedto, '|');
       
  5009 
       
  5010 		foreach ( $p as $para ) {
       
  5011 			if ( strpos($para, $pagelinkedto) !== false ) { // it exists, but is it a link?
       
  5012 				preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context);
       
  5013 
       
  5014 				// If the URL isn't in a link context, keep looking
       
  5015 				if ( empty($context) )
       
  5016 					continue;
       
  5017 
       
  5018 				// We're going to use this fake tag to mark the context in a bit
       
  5019 				// the marker is needed in case the link text appears more than once in the paragraph
       
  5020 				$excerpt = preg_replace('|\</?wpcontext\>|', '', $para);
       
  5021 
       
  5022 				// prevent really long link text
       
  5023 				if ( strlen($context[1]) > 100 )
       
  5024 					$context[1] = substr($context[1], 0, 100) . '...';
       
  5025 
       
  5026 				$marker = '<wpcontext>'.$context[1].'</wpcontext>';    // set up our marker
       
  5027 				$excerpt= str_replace($context[0], $marker, $excerpt); // swap out the link for our marker
       
  5028 				$excerpt = strip_tags($excerpt, '<wpcontext>');        // strip all tags but our context marker
       
  5029 				$excerpt = trim($excerpt);
       
  5030 				$preg_marker = preg_quote($marker, '|');
       
  5031 				$excerpt = preg_replace("|.*?\s(.{0,100}$preg_marker.{0,100})\s.*|s", '$1', $excerpt);
       
  5032 				$excerpt = strip_tags($excerpt); // YES, again, to remove the marker wrapper
       
  5033 				break;
       
  5034 			}
       
  5035 		}
       
  5036 
       
  5037 		if ( empty($context) ) // Link to target not found
       
  5038 			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.'));
       
  5039 
       
  5040 		$pagelinkedfrom = str_replace('&', '&amp;', $pagelinkedfrom);
       
  5041 
       
  5042 		$context = '[...] ' . esc_html( $excerpt ) . ' [...]';
       
  5043 		$pagelinkedfrom = $wpdb->escape( $pagelinkedfrom );
       
  5044 
       
  5045 		$comment_post_ID = (int) $post_ID;
       
  5046 		$comment_author = $title;
       
  5047 		$comment_author_email = '';
       
  5048 		$this->escape($comment_author);
       
  5049 		$comment_author_url = $pagelinkedfrom;
       
  5050 		$comment_content = $context;
       
  5051 		$this->escape($comment_content);
       
  5052 		$comment_type = 'pingback';
       
  5053 
       
  5054 		$commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_author_email', 'comment_content', 'comment_type');
       
  5055 
       
  5056 		$comment_ID = wp_new_comment($commentdata);
       
  5057 		do_action('pingback_post', $comment_ID);
       
  5058 
       
  5059 		return sprintf(__('Pingback from %1$s to %2$s registered. Keep the web talking! :-)'), $pagelinkedfrom, $pagelinkedto);
       
  5060 	}
       
  5061 
       
  5062 	/**
       
  5063 	 * Retrieve array of URLs that pingbacked the given URL.
       
  5064 	 *
       
  5065 	 * Specs on http://www.aquarionics.com/misc/archives/blogite/0198.html
       
  5066 	 *
       
  5067 	 * @since 1.5.0
       
  5068 	 *
       
  5069 	 * @param array $args Method parameters.
       
  5070 	 * @return array
       
  5071 	 */
       
  5072 	function pingback_extensions_getPingbacks($args) {
       
  5073 
       
  5074 		global $wpdb;
       
  5075 
       
  5076 		do_action('xmlrpc_call', 'pingback.extensions.getPingbacks');
       
  5077 
       
  5078 		$this->escape($args);
       
  5079 
       
  5080 		$url = $args;
       
  5081 
       
  5082 		$post_ID = url_to_postid($url);
       
  5083 		if ( !$post_ID ) {
       
  5084 			// We aren't sure that the resource is available and/or pingback enabled
       
  5085 	  		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.'));
       
  5086 		}
       
  5087 
       
  5088 		$actual_post = wp_get_single_post($post_ID, ARRAY_A);
       
  5089 
       
  5090 		if ( !$actual_post ) {
       
  5091 			// No such post = resource not found
       
  5092 	  		return new IXR_Error(32, __('The specified target URL does not exist.'));
       
  5093 		}
       
  5094 
       
  5095 		$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) );
       
  5096 
       
  5097 		if ( !$comments )
       
  5098 			return array();
       
  5099 
       
  5100 		$pingbacks = array();
       
  5101 		foreach ( $comments as $comment ) {
       
  5102 			if ( 'pingback' == $comment->comment_type )
       
  5103 				$pingbacks[] = $comment->comment_author_url;
       
  5104 		}
       
  5105 
       
  5106 		return $pingbacks;
       
  5107 	}
       
  5108 }