+ /**
+ * Edit comment.
+ *
+ * @since 2.7.0
+ *
+ * @param array $args Method parameters.
+ * @return bool True, on success.
+ */
+ function wp_editComment($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $comment_ID = (int) $args[3];
+ $content_struct = $args[4];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ if ( !current_user_can( 'moderate_comments' ) )
+ return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this blog.' ) );
+
+ do_action('xmlrpc_call', 'wp.editComment');
+
+ if ( ! get_comment($comment_ID) )
+ return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
+
+ if ( isset($content_struct['status']) ) {
+ $statuses = get_comment_statuses();
+ $statuses = array_keys($statuses);
+
+ if ( ! in_array($content_struct['status'], $statuses) )
+ return new IXR_Error( 401, __( 'Invalid comment status.' ) );
+ $comment_approved = $content_struct['status'];
+ }
+
+ // Do some timestamp voodoo
+ if ( !empty( $content_struct['date_created_gmt'] ) ) {
+ $dateCreated = str_replace( 'Z', '', $content_struct['date_created_gmt']->getIso() ) . 'Z'; // We know this is supposed to be GMT, so we're going to slap that Z on there by force
+ $comment_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
+ $comment_date_gmt = iso8601_to_datetime($dateCreated, GMT);
+ }
+
+ if ( isset($content_struct['content']) )
+ $comment_content = $content_struct['content'];
+
+ if ( isset($content_struct['author']) )
+ $comment_author = $content_struct['author'];
+
+ if ( isset($content_struct['author_url']) )
+ $comment_author_url = $content_struct['author_url'];
+
+ if ( isset($content_struct['author_email']) )
+ $comment_author_email = $content_struct['author_email'];
+
+ // We've got all the data -- post it:
+ $comment = compact('comment_ID', 'comment_content', 'comment_approved', 'comment_date', 'comment_date_gmt', 'comment_author', 'comment_author_email', 'comment_author_url');
+
+ $result = wp_update_comment($comment);
+ if ( is_wp_error( $result ) )
+ return new IXR_Error(500, $result->get_error_message());
+
+ if ( !$result )
+ return new IXR_Error(500, __('Sorry, the comment could not be edited. Something wrong happened.'));
+
+ return true;
+ }
+
+ /**
+ * Create new comment.
+ *
+ * @since 2.7.0
+ *
+ * @param array $args Method parameters.
+ * @return mixed {@link wp_new_comment()}
+ */
+ function wp_newComment($args) {
+ global $wpdb;
+
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $post = $args[3];
+ $content_struct = $args[4];
+
+ $allow_anon = apply_filters('xmlrpc_allow_anonymous_comments', false);
+
+ $user = $this->login($username, $password);
+
+ if ( !$user ) {
+ $logged_in = false;
+ if ( $allow_anon && get_option('comment_registration') )
+ return new IXR_Error( 403, __( 'You must be registered to comment' ) );
+ else if ( !$allow_anon )
+ return $this->error;
+ } else {
+ $logged_in = true;
+ }
+
+ if ( is_numeric($post) )
+ $post_id = absint($post);
+ else
+ $post_id = url_to_postid($post);
+
+ if ( ! $post_id )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( ! get_post($post_id) )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ $comment['comment_post_ID'] = $post_id;
+
+ if ( $logged_in ) {
+ $comment['comment_author'] = $wpdb->escape( $user->display_name );
+ $comment['comment_author_email'] = $wpdb->escape( $user->user_email );
+ $comment['comment_author_url'] = $wpdb->escape( $user->user_url );
+ $comment['user_ID'] = $user->ID;
+ } else {
+ $comment['comment_author'] = '';
+ if ( isset($content_struct['author']) )
+ $comment['comment_author'] = $content_struct['author'];
+
+ $comment['comment_author_email'] = '';
+ if ( isset($content_struct['author_email']) )
+ $comment['comment_author_email'] = $content_struct['author_email'];
+
+ $comment['comment_author_url'] = '';
+ if ( isset($content_struct['author_url']) )
+ $comment['comment_author_url'] = $content_struct['author_url'];
+
+ $comment['user_ID'] = 0;
+
+ if ( get_option('require_name_email') ) {
+ if ( 6 > strlen($comment['comment_author_email']) || '' == $comment['comment_author'] )
+ return new IXR_Error( 403, __( 'Comment author name and email are required' ) );
+ elseif ( !is_email($comment['comment_author_email']) )
+ return new IXR_Error( 403, __( 'A valid email address is required' ) );
+ }
+ }
+
+ $comment['comment_parent'] = isset($content_struct['comment_parent']) ? absint($content_struct['comment_parent']) : 0;
+
+ $comment['comment_content'] = $content_struct['content'];
+
+ do_action('xmlrpc_call', 'wp.newComment');
+
+ return wp_new_comment($comment);
+ }
+
+ /**
+ * Retrieve all of the comment status.
+ *
+ * @since 2.7.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getCommentStatusList($args) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ if ( !current_user_can( 'moderate_comments' ) )
+ return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) );
+
+ do_action('xmlrpc_call', 'wp.getCommentStatusList');
+
+ return get_comment_statuses( );
+ }
+
+ /**
+ * Retrieve comment count.
+ *
+ * @since 2.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getCommentCount( $args ) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $post_id = (int) $args[3];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ if( !current_user_can( 'edit_posts' ) ) {
+ return new IXR_Error( 403, __( 'You are not allowed access to details about comments.' ) );
+ }
+
+ do_action('xmlrpc_call', 'wp.getCommentCount');
+
+ $count = wp_count_comments( $post_id );
+ return array(
+ "approved" => $count->approved,
+ "awaiting_moderation" => $count->moderated,
+ "spam" => $count->spam,
+ "total_comments" => $count->total_comments
+ );
+ }
+
+ /**
+ * Retrieve post statuses.
+ *
+ * @since 2.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getPostStatusList( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ if( !current_user_can( 'edit_posts' ) ) {
+ return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) );
+ }
+
+ do_action('xmlrpc_call', 'wp.getPostStatusList');
+
+ return get_post_statuses( );
+ }
+
+ /**
+ * Retrieve page statuses.
+ *
+ * @since 2.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getPageStatusList( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ if( !current_user_can( 'edit_posts' ) ) {
+ return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) );
+ }
+
+ do_action('xmlrpc_call', 'wp.getPageStatusList');
+
+ return get_page_statuses( );
+ }
+
+ /**
+ * Retrieve page templates.
+ *
+ * @since 2.6.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getPageTemplates( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ if( !current_user_can( 'edit_pages' ) ) {
+ return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) );
+ }
+
+ $templates = get_page_templates( );
+ $templates['Default'] = 'default';
+
+ return $templates;
+ }
+
+ /**
+ * Retrieve blog options.
+ *
+ * @since 2.6.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getOptions( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $options = (array) $args[3];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ // If no specific options where asked for, return all of them
+ if (count( $options ) == 0 ) {
+ $options = array_keys($this->blog_options);
+ }
+
+ return $this->_getOptions($options);
+ }
+
+ /**
+ * Retrieve blog options value from list.
+ *
+ * @since 2.6.0
+ *
+ * @param array $options Options to retrieve.
+ * @return array
+ */
+ function _getOptions($options)
+ {
+ $data = array( );
+ foreach( $options as $option ) {
+ if( array_key_exists( $option, $this->blog_options ) )
+ {
+ $data[$option] = $this->blog_options[$option];
+ //Is the value static or dynamic?
+ if( isset( $data[$option]['option'] ) ) {
+ $data[$option]['value'] = get_option( $data[$option]['option'] );
+ unset($data[$option]['option']);
+ }
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Update blog options.
+ *
+ * @since 2.6.0
+ *
+ * @param array $args Method parameters.
+ * @return unknown
+ */
+ function wp_setOptions( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $options = (array) $args[3];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ if( !current_user_can( 'manage_options' ) )
+ return new IXR_Error( 403, __( 'You are not allowed to update options.' ) );
+
+ foreach( $options as $o_name => $o_value ) {
+ $option_names[] = $o_name;
+ if( !array_key_exists( $o_name, $this->blog_options ) )
+ continue;
+
+ if( $this->blog_options[$o_name]['readonly'] == true )
+ continue;
+
+ update_option( $this->blog_options[$o_name]['option'], $o_value );
+ }
+
+ //Now return the updated values
+ return $this->_getOptions($option_names);
+ }
+
+ /* Blogger API functions.
+ * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/
+ */
+
+ /**
+ * Retrieve blogs that user owns.
+ *
+ * Will make more sense once we support multiple blogs.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function blogger_getUsersBlogs($args) {
+
+ $this->escape($args);
+
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ do_action('xmlrpc_call', 'blogger.getUsersBlogs');
+
+ $is_admin = current_user_can('manage_options');
+
+ $struct = array(
+ 'isAdmin' => $is_admin,
+ 'url' => get_option('home') . '/',
+ 'blogid' => '1',
+ 'blogName' => get_option('blogname'),
+ 'xmlrpc' => site_url( 'xmlrpc.php' )
+ );
+
+ return array($struct);
+ }
+
+ /**
+ * Retrieve user's data.
+ *
+ * Gives your client some info about you, so you don't have to.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function blogger_getUserInfo($args) {
+
+ $this->escape($args);
+
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ if( !current_user_can( 'edit_posts' ) )
+ return new IXR_Error( 401, __( 'Sorry, you do not have access to user data on this blog.' ) );
+
+ do_action('xmlrpc_call', 'blogger.getUserInfo');
+
+ $struct = array(
+ 'nickname' => $user->nickname,
+ 'userid' => $user->ID,
+ 'url' => $user->user_url,
+ 'lastname' => $user->last_name,
+ 'firstname' => $user->first_name
+ );
+
+ return $struct;
+ }
+
+ /**
+ * Retrieve post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function blogger_getPost($args) {
+
+ $this->escape($args);
+
+ $post_ID = (int) $args[1];
+ $username = $args[2];
+ $password = $args[3];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ if( !current_user_can( 'edit_post', $post_ID ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
+
+ do_action('xmlrpc_call', 'blogger.getPost');
+
+ $post_data = wp_get_single_post($post_ID, ARRAY_A);
+
+ $categories = implode(',', wp_get_post_categories($post_ID));
+
+ $content = '<title>'.stripslashes($post_data['post_title']).'</title>';
+ $content .= '<category>'.$categories.'</category>';
+ $content .= stripslashes($post_data['post_content']);
+
+ $struct = array(
+ 'userid' => $post_data['post_author'],
+ 'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'], false)),
+ 'content' => $content,
+ 'postid' => $post_data['ID']
+ );
+
+ return $struct;
+ }
+
+ /**
+ * Retrieve list of recent posts.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function blogger_getRecentPosts($args) {
+
+ $this->escape($args);
+
+ $blog_ID = (int) $args[1]; /* though we don't use it yet */
+ $username = $args[2];
+ $password = $args[3];
+ $num_posts = $args[4];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ do_action('xmlrpc_call', 'blogger.getRecentPosts');
+
+ $posts_list = wp_get_recent_posts($num_posts);
+
+ if (!$posts_list) {
+ $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
+ return $this->error;
+ }
+
+ foreach ($posts_list as $entry) {
+ if( !current_user_can( 'edit_post', $entry['ID'] ) )
+ continue;
+
+ $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false);
+ $categories = implode(',', wp_get_post_categories($entry['ID']));
+
+ $content = '<title>'.stripslashes($entry['post_title']).'</title>';
+ $content .= '<category>'.$categories.'</category>';
+ $content .= stripslashes($entry['post_content']);
+
+ $struct[] = array(
+ 'userid' => $entry['post_author'],
+ 'dateCreated' => new IXR_Date($post_date),
+ 'content' => $content,
+ 'postid' => $entry['ID'],
+ );
+
+ }
+
+ $recent_posts = array();
+ for ($j=0; $j<count($struct); $j++) {
+ array_push($recent_posts, $struct[$j]);
+ }
+
+ return $recent_posts;
+ }
+
+ /**
+ * Retrieve blog_filename content.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return string
+ */
+ function blogger_getTemplate($args) {
+
+ $this->escape($args);
+
+ $blog_ID = (int) $args[1];
+ $username = $args[2];
+ $password = $args[3];
+ $template = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ do_action('xmlrpc_call', 'blogger.getTemplate');
+
+ if ( !current_user_can('edit_themes') ) {
+ return new IXR_Error(401, __('Sorry, this user can not edit the template.'));
+ }
+
+ /* warning: here we make the assumption that the blog's URL is on the same server */
+ $filename = get_option('home') . '/';
+ $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
+
+ $f = fopen($filename, 'r');
+ $content = fread($f, filesize($filename));
+ fclose($f);
+
+ /* so it is actually editable with a windows/mac client */
+ // 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);
+
+ return $content;
+ }
+
+ /**
+ * Updates the content of blog_filename.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return bool True when done.
+ */
+ function blogger_setTemplate($args) {
+
+ $this->escape($args);
+
+ $blog_ID = (int) $args[1];
+ $username = $args[2];
+ $password = $args[3];
+ $content = $args[4];
+ $template = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ do_action('xmlrpc_call', 'blogger.setTemplate');
+
+ if ( !current_user_can('edit_themes') ) {
+ return new IXR_Error(401, __('Sorry, this user cannot edit the template.'));
+ }
+
+ /* warning: here we make the assumption that the blog's URL is on the same server */
+ $filename = get_option('home') . '/';
+ $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
+
+ if ($f = fopen($filename, 'w+')) {
+ fwrite($f, $content);
+ fclose($f);
+ } else {
+ return new IXR_Error(500, __('Either the file is not writable, or something wrong happened. The file has not been updated.'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Create new post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return int
+ */
+ function blogger_newPost($args) {
+
+ $this->escape($args);
+
+ $blog_ID = (int) $args[1]; /* though we don't use it yet */
+ $username = $args[2];
+ $password = $args[3];
+ $content = $args[4];
+ $publish = $args[5];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ do_action('xmlrpc_call', 'blogger.newPost');
+
+ $cap = ($publish) ? 'publish_posts' : 'edit_posts';
+ if ( !current_user_can($cap) )
+ return new IXR_Error(401, __('Sorry, you are not allowed to post on this blog.'));
+
+ $post_status = ($publish) ? 'publish' : 'draft';
+
+ $post_author = $user->ID;
+
+ $post_title = xmlrpc_getposttitle($content);
+ $post_category = xmlrpc_getpostcategory($content);
+ $post_content = xmlrpc_removepostdata($content);
+
+ $post_date = current_time('mysql');
+ $post_date_gmt = current_time('mysql', 1);
+
+ $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status');
+
+ $post_ID = wp_insert_post($post_data);
+ if ( is_wp_error( $post_ID ) )
+ return new IXR_Error(500, $post_ID->get_error_message());
+
+ if (!$post_ID)
+ return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
+
+ $this->attach_uploads( $post_ID, $post_content );
+
+ logIO('O', "Posted ! ID: $post_ID");
+
+ return $post_ID;
+ }
+
+ /**
+ * Edit a post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return bool true when done.
+ */
+ function blogger_editPost($args) {
+
+ $this->escape($args);
+
+ $post_ID = (int) $args[1];
+ $username = $args[2];
+ $password = $args[3];
+ $content = $args[4];
+ $publish = $args[5];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ do_action('xmlrpc_call', 'blogger.editPost');
+
+ $actual_post = wp_get_single_post($post_ID,ARRAY_A);
+
+ if (!$actual_post || $actual_post['post_type'] != 'post') {
+ return new IXR_Error(404, __('Sorry, no such post.'));
+ }
+
+ $this->escape($actual_post);
+
+ if ( !current_user_can('edit_post', $post_ID) )
+ return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.'));
+
+ extract($actual_post, EXTR_SKIP);
+
+ if ( ('publish' == $post_status) && !current_user_can('publish_posts') )
+ return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
+
+ $post_title = xmlrpc_getposttitle($content);
+ $post_category = xmlrpc_getpostcategory($content);
+ $post_content = xmlrpc_removepostdata($content);
+
+ $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
+
+ $result = wp_update_post($postdata);
+
+ if (!$result) {
+ return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.'));
+ }
+ $this->attach_uploads( $ID, $post_content );
+
+ return true;
+ }
+
+ /**
+ * Remove a post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return bool True when post is deleted.
+ */
+ function blogger_deletePost($args) {
+ $this->escape($args);
+
+ $post_ID = (int) $args[1];
+ $username = $args[2];
+ $password = $args[3];
+ $publish = $args[4];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ do_action('xmlrpc_call', 'blogger.deletePost');
+
+ $actual_post = wp_get_single_post($post_ID,ARRAY_A);
+
+ if (!$actual_post || $actual_post['post_type'] != 'post') {
+ return new IXR_Error(404, __('Sorry, no such post.'));
+ }
+
+ if ( !current_user_can('edit_post', $post_ID) )
+ return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.'));
+
+ $result = wp_delete_post($post_ID);
+
+ if (!$result) {
+ return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.'));
+ }
+
+ return true;
+ }