WordPress.org

Make WordPress Core

Ticket #14814: refactor-xml-rpc-class.14814.diff

File refactor-xml-rpc-class.14814.diff, 186.6 KB (added by filosofo, 5 years ago)
  • wp-includes/class-xmlrpc-server.php

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

     
    5252 
    5353include_once(ABSPATH . 'wp-admin/includes/admin.php'); 
    5454include_once(ABSPATH . WPINC . '/class-IXR.php'); 
     55include_once(ABSPATH . WPINC . '/class-xmlrpc-server.php'); 
    5556 
    5657// Turn off all warnings and errors. 
    5758// error_reporting(0); 
     
    7172 */ 
    7273$xmlrpc_logging = 0; 
    7374 
    74 /** 
    75  * logIO() - Writes logging info to a file. 
    76  * 
    77  * @uses $xmlrpc_logging 
    78  * @package WordPress 
    79  * @subpackage Logging 
    80  * 
    81  * @param string $io Whether input or output 
    82  * @param string $msg Information describing logging reason. 
    83  * @return bool Always return true 
    84  */ 
    85 function logIO($io,$msg) { 
    86         global $xmlrpc_logging; 
    87         if ($xmlrpc_logging) { 
    88                 $fp = fopen("../xmlrpc.log","a+"); 
    89                 $date = gmdate("Y-m-d H:i:s "); 
    90                 $iot = ($io == "I") ? " Input: " : " Output: "; 
    91                 fwrite($fp, "\n\n".$date.$iot.$msg); 
    92                 fclose($fp); 
    93         } 
    94         return true; 
    95 } 
    96  
    9775if ( isset($HTTP_RAW_POST_DATA) ) 
    9876        logIO("I", $HTTP_RAW_POST_DATA); 
    9977 
    100 /** 
    101  * WordPress XMLRPC server implementation. 
    102  * 
    103  * Implements compatability for Blogger API, MetaWeblog API, MovableType, and 
    104  * pingback. Additional WordPress API for managing comments, pages, posts, 
    105  * options, etc. 
    106  * 
    107  * Since WordPress 2.6.0, WordPress XMLRPC server can be disabled in the 
    108  * administration panels. 
    109  * 
    110  * @package WordPress 
    111  * @subpackage Publishing 
    112  * @since 1.5.0 
    113  */ 
    114 class wp_xmlrpc_server extends IXR_Server { 
     78$xmlrpc_server_class = apply_filters('wp_xmlrpc_server_class', 'wp_xmlrpc_server'); 
    11579 
    116         /** 
    117          * Register all of the XMLRPC methods that XMLRPC server understands. 
    118          * 
    119          * PHP4 constructor and sets up server and method property. Passes XMLRPC 
    120          * methods through the 'xmlrpc_methods' filter to allow plugins to extend 
    121          * or replace XMLRPC methods. 
    122          * 
    123          * @since 1.5.0 
    124          * 
    125          * @return wp_xmlrpc_server 
    126          */ 
    127         function wp_xmlrpc_server() { 
    128                 $this->methods = array( 
    129                         // WordPress API 
    130                         'wp.getUsersBlogs'              => 'this:wp_getUsersBlogs', 
    131                         'wp.getPage'                    => 'this:wp_getPage', 
    132                         'wp.getPages'                   => 'this:wp_getPages', 
    133                         'wp.newPage'                    => 'this:wp_newPage', 
    134                         'wp.deletePage'                 => 'this:wp_deletePage', 
    135                         'wp.editPage'                   => 'this:wp_editPage', 
    136                         'wp.getPageList'                => 'this:wp_getPageList', 
    137                         'wp.getAuthors'                 => 'this:wp_getAuthors', 
    138                         'wp.getCategories'              => 'this:mw_getCategories',             // Alias 
    139                         'wp.getTags'                    => 'this:wp_getTags', 
    140                         'wp.newCategory'                => 'this:wp_newCategory', 
    141                         'wp.deleteCategory'             => 'this:wp_deleteCategory', 
    142                         'wp.suggestCategories'  => 'this:wp_suggestCategories', 
    143                         'wp.uploadFile'                 => 'this:mw_newMediaObject',    // Alias 
    144                         'wp.getCommentCount'    => 'this:wp_getCommentCount', 
    145                         'wp.getPostStatusList'  => 'this:wp_getPostStatusList', 
    146                         'wp.getPageStatusList'  => 'this:wp_getPageStatusList', 
    147                         'wp.getPageTemplates'   => 'this:wp_getPageTemplates', 
    148                         'wp.getOptions'                 => 'this:wp_getOptions', 
    149                         'wp.setOptions'                 => 'this:wp_setOptions', 
    150                         'wp.getComment'                 => 'this:wp_getComment', 
    151                         'wp.getComments'                => 'this:wp_getComments', 
    152                         'wp.deleteComment'              => 'this:wp_deleteComment', 
    153                         'wp.editComment'                => 'this:wp_editComment', 
    154                         'wp.newComment'                 => 'this:wp_newComment', 
    155                         'wp.getCommentStatusList' => 'this:wp_getCommentStatusList', 
    156  
    157                         // Blogger API 
    158                         'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs', 
    159                         'blogger.getUserInfo' => 'this:blogger_getUserInfo', 
    160                         'blogger.getPost' => 'this:blogger_getPost', 
    161                         'blogger.getRecentPosts' => 'this:blogger_getRecentPosts', 
    162                         'blogger.getTemplate' => 'this:blogger_getTemplate', 
    163                         'blogger.setTemplate' => 'this:blogger_setTemplate', 
    164                         'blogger.newPost' => 'this:blogger_newPost', 
    165                         'blogger.editPost' => 'this:blogger_editPost', 
    166                         'blogger.deletePost' => 'this:blogger_deletePost', 
    167  
    168                         // MetaWeblog API (with MT extensions to structs) 
    169                         'metaWeblog.newPost' => 'this:mw_newPost', 
    170                         'metaWeblog.editPost' => 'this:mw_editPost', 
    171                         'metaWeblog.getPost' => 'this:mw_getPost', 
    172                         'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts', 
    173                         'metaWeblog.getCategories' => 'this:mw_getCategories', 
    174                         'metaWeblog.newMediaObject' => 'this:mw_newMediaObject', 
    175  
    176                         // MetaWeblog API aliases for Blogger API 
    177                         // see http://www.xmlrpc.com/stories/storyReader$2460 
    178                         'metaWeblog.deletePost' => 'this:blogger_deletePost', 
    179                         'metaWeblog.getTemplate' => 'this:blogger_getTemplate', 
    180                         'metaWeblog.setTemplate' => 'this:blogger_setTemplate', 
    181                         'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs', 
    182  
    183                         // MovableType API 
    184                         'mt.getCategoryList' => 'this:mt_getCategoryList', 
    185                         'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles', 
    186                         'mt.getPostCategories' => 'this:mt_getPostCategories', 
    187                         'mt.setPostCategories' => 'this:mt_setPostCategories', 
    188                         'mt.supportedMethods' => 'this:mt_supportedMethods', 
    189                         'mt.supportedTextFilters' => 'this:mt_supportedTextFilters', 
    190                         'mt.getTrackbackPings' => 'this:mt_getTrackbackPings', 
    191                         'mt.publishPost' => 'this:mt_publishPost', 
    192  
    193                         // PingBack 
    194                         'pingback.ping' => 'this:pingback_ping', 
    195                         'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks', 
    196  
    197                         'demo.sayHello' => 'this:sayHello', 
    198                         'demo.addTwoNumbers' => 'this:addTwoNumbers' 
    199                 ); 
    200  
    201                 $this->initialise_blog_option_info( ); 
    202                 $this->methods = apply_filters('xmlrpc_methods', $this->methods); 
    203         } 
    204  
    205         function serve_request() { 
    206                 $this->IXR_Server($this->methods); 
    207         } 
    208  
    209         /** 
    210          * Test XMLRPC API by saying, "Hello!" to client. 
    211          * 
    212          * @since 1.5.0 
    213          * 
    214          * @param array $args Method Parameters. 
    215          * @return string 
    216          */ 
    217         function sayHello($args) { 
    218                 return 'Hello!'; 
    219         } 
    220  
    221         /** 
    222          * Test XMLRPC API by adding two numbers for client. 
    223          * 
    224          * @since 1.5.0 
    225          * 
    226          * @param array $args Method Parameters. 
    227          * @return int 
    228          */ 
    229         function addTwoNumbers($args) { 
    230                 $number1 = $args[0]; 
    231                 $number2 = $args[1]; 
    232                 return $number1 + $number2; 
    233         } 
    234  
    235         /** 
    236          * Check user's credentials. 
    237          * 
    238          * @since 1.5.0 
    239          * 
    240          * @param string $user_login User's username. 
    241          * @param string $user_pass User's password. 
    242          * @return bool Whether authentication passed. 
    243          * @deprecated use wp_xmlrpc_server::login 
    244          * @see wp_xmlrpc_server::login 
    245          */ 
    246         function login_pass_ok($user_login, $user_pass) { 
    247                 if ( !get_option( 'enable_xmlrpc' ) ) { 
    248                         $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.  An admin user can enable them at %s'),  admin_url('options-writing.php') ) ); 
    249                         return false; 
    250                 } 
    251  
    252                 if (!user_pass_ok($user_login, $user_pass)) { 
    253                         $this->error = new IXR_Error(403, __('Bad login/pass combination.')); 
    254                         return false; 
    255                 } 
    256                 return true; 
    257         } 
    258  
    259         /** 
    260          * Log user in. 
    261          * 
    262          * @since 2.8 
    263          * 
    264          * @param string $username User's username. 
    265          * @param string $password User's password. 
    266          * @return mixed WP_User object if authentication passed, false otherwise 
    267          */ 
    268         function login($username, $password) { 
    269                 if ( !get_option( 'enable_xmlrpc' ) ) { 
    270                         $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.  An admin user can enable them at %s'),  admin_url('options-writing.php') ) ); 
    271                         return false; 
    272                 } 
    273  
    274                 $user = wp_authenticate($username, $password); 
    275  
    276                 if (is_wp_error($user)) { 
    277                         $this->error = new IXR_Error(403, __('Bad login/pass combination.')); 
    278                         return false; 
    279                 } 
    280  
    281                 wp_set_current_user( $user->ID ); 
    282                 return $user; 
    283         } 
    284  
    285         /** 
    286          * Sanitize string or array of strings for database. 
    287          * 
    288          * @since 1.5.2 
    289          * 
    290          * @param string|array $array Sanitize single string or array of strings. 
    291          * @return string|array Type matches $array and sanitized for the database. 
    292          */ 
    293         function escape(&$array) { 
    294                 global $wpdb; 
    295  
    296                 if (!is_array($array)) { 
    297                         return($wpdb->escape($array)); 
    298                 } else { 
    299                         foreach ( (array) $array as $k => $v ) { 
    300                                 if ( is_array($v) ) { 
    301                                         $this->escape($array[$k]); 
    302                                 } else if ( is_object($v) ) { 
    303                                         //skip 
    304                                 } else { 
    305                                         $array[$k] = $wpdb->escape($v); 
    306                                 } 
    307                         } 
    308                 } 
    309         } 
    310  
    311         /** 
    312          * Retrieve custom fields for post. 
    313          * 
    314          * @since 2.5.0 
    315          * 
    316          * @param int $post_id Post ID. 
    317          * @return array Custom fields, if exist. 
    318          */ 
    319         function get_custom_fields($post_id) { 
    320                 $post_id = (int) $post_id; 
    321  
    322                 $custom_fields = array(); 
    323  
    324                 foreach ( (array) has_meta($post_id) as $meta ) { 
    325                         // Don't expose protected fields. 
    326                         if ( strpos($meta['meta_key'], '_wp_') === 0 ) { 
    327                                 continue; 
    328                         } 
    329  
    330                         $custom_fields[] = array( 
    331                                 "id"    => $meta['meta_id'], 
    332                                 "key"   => $meta['meta_key'], 
    333                                 "value" => $meta['meta_value'] 
    334                         ); 
    335                 } 
    336  
    337                 return $custom_fields; 
    338         } 
    339  
    340         /** 
    341          * Set custom fields for post. 
    342          * 
    343          * @since 2.5.0 
    344          * 
    345          * @param int $post_id Post ID. 
    346          * @param array $fields Custom fields. 
    347          */ 
    348         function set_custom_fields($post_id, $fields) { 
    349                 $post_id = (int) $post_id; 
    350  
    351                 foreach ( (array) $fields as $meta ) { 
    352                         if ( isset($meta['id']) ) { 
    353                                 $meta['id'] = (int) $meta['id']; 
    354  
    355                                 if ( isset($meta['key']) ) { 
    356                                         update_meta($meta['id'], $meta['key'], $meta['value']); 
    357                                 } 
    358                                 else { 
    359                                         delete_meta($meta['id']); 
    360                                 } 
    361                         } 
    362                         else { 
    363                                 $_POST['metakeyinput'] = $meta['key']; 
    364                                 $_POST['metavalue'] = $meta['value']; 
    365                                 add_meta($post_id); 
    366                         } 
    367                 } 
    368         } 
    369  
    370         /** 
    371          * Set up blog options property. 
    372          * 
    373          * Passes property through 'xmlrpc_blog_options' filter. 
    374          * 
    375          * @since 2.6.0 
    376          */ 
    377         function initialise_blog_option_info( ) { 
    378                 global $wp_version; 
    379  
    380                 $this->blog_options = array( 
    381                         // Read only options 
    382                         'software_name'         => array( 
    383                                 'desc'                  => __( 'Software Name' ), 
    384                                 'readonly'              => true, 
    385                                 'value'                 => 'WordPress' 
    386                         ), 
    387                         'software_version'      => array( 
    388                                 'desc'                  => __( 'Software Version' ), 
    389                                 'readonly'              => true, 
    390                                 'value'                 => $wp_version 
    391                         ), 
    392                         'blog_url'                      => array( 
    393                                 'desc'                  => __( 'Site URL' ), 
    394                                 'readonly'              => true, 
    395                                 'option'                => 'siteurl' 
    396                         ), 
    397  
    398                         // Updatable options 
    399                         'time_zone'                     => array( 
    400                                 'desc'                  => __( 'Time Zone' ), 
    401                                 'readonly'              => false, 
    402                                 'option'                => 'gmt_offset' 
    403                         ), 
    404                         'blog_title'            => array( 
    405                                 'desc'                  => __( 'Site Title' ), 
    406                                 'readonly'              => false, 
    407                                 'option'                        => 'blogname' 
    408                         ), 
    409                         'blog_tagline'          => array( 
    410                                 'desc'                  => __( 'Site Tagline' ), 
    411                                 'readonly'              => false, 
    412                                 'option'                => 'blogdescription' 
    413                         ), 
    414                         'date_format'           => array( 
    415                                 'desc'                  => __( 'Date Format' ), 
    416                                 'readonly'              => false, 
    417                                 'option'                => 'date_format' 
    418                         ), 
    419                         'time_format'           => array( 
    420                                 'desc'                  => __( 'Time Format' ), 
    421                                 'readonly'              => false, 
    422                                 'option'                => 'time_format' 
    423                         ), 
    424                         'users_can_register'    => array( 
    425                                 'desc'                  => __( 'Allow new users to sign up' ), 
    426                                 'readonly'              => false, 
    427                                 'option'                => 'users_can_register' 
    428                         ) 
    429                 ); 
    430  
    431                 $this->blog_options = apply_filters( 'xmlrpc_blog_options', $this->blog_options ); 
    432         } 
    433  
    434         /** 
    435          * Retrieve the blogs of the user. 
    436          * 
    437          * @since 2.6.0 
    438          * 
    439          * @param array $args Method parameters. 
    440          * @return array 
    441          */ 
    442         function wp_getUsersBlogs( $args ) { 
    443                 global $current_site; 
    444                 // If this isn't on WPMU then just use blogger_getUsersBlogs 
    445                 if ( !is_multisite() ) { 
    446                         array_unshift( $args, 1 ); 
    447                         return $this->blogger_getUsersBlogs( $args ); 
    448                 } 
    449  
    450                 $this->escape( $args ); 
    451  
    452                 $username = $args[0]; 
    453                 $password = $args[1]; 
    454  
    455                 if ( !$user = $this->login($username, $password) ) 
    456                         return $this->error; 
    457  
    458  
    459                 do_action( 'xmlrpc_call', 'wp.getUsersBlogs' ); 
    460  
    461                 $blogs = (array) get_blogs_of_user( $user->ID ); 
    462                 $struct = array( ); 
    463  
    464                 foreach ( $blogs as $blog ) { 
    465                         // Don't include blogs that aren't hosted at this site 
    466                         if ( $blog->site_id != $current_site->id ) 
    467                                 continue; 
    468  
    469                         $blog_id = $blog->userblog_id; 
    470                         switch_to_blog($blog_id); 
    471                         $is_admin = current_user_can('manage_options'); 
    472  
    473                         $struct[] = array( 
    474                                 'isAdmin'               => $is_admin, 
    475                                 'url'                   => get_option( 'home' ) . '/', 
    476                                 'blogid'                => $blog_id, 
    477                                 'blogName'              => get_option( 'blogname' ), 
    478                                 'xmlrpc'                => site_url( 'xmlrpc.php' ) 
    479                         ); 
    480  
    481                         restore_current_blog( ); 
    482                 } 
    483  
    484                 return $struct; 
    485         } 
    486  
    487         /** 
    488          * Retrieve page. 
    489          * 
    490          * @since 2.2.0 
    491          * 
    492          * @param array $args Method parameters. 
    493          * @return array 
    494          */ 
    495         function wp_getPage($args) { 
    496                 $this->escape($args); 
    497  
    498                 $blog_id        = (int) $args[0]; 
    499                 $page_id        = (int) $args[1]; 
    500                 $username       = $args[2]; 
    501                 $password       = $args[3]; 
    502  
    503                 if ( !$user = $this->login($username, $password) ) { 
    504                         return $this->error; 
    505                 } 
    506  
    507                 if ( !current_user_can( 'edit_page', $page_id ) ) 
    508                         return new IXR_Error( 401, __( 'Sorry, you cannot edit this page.' ) ); 
    509  
    510                 do_action('xmlrpc_call', 'wp.getPage'); 
    511  
    512                 // Lookup page info. 
    513                 $page = get_page($page_id); 
    514  
    515                 // If we found the page then format the data. 
    516                 if ( $page->ID && ($page->post_type == "page") ) { 
    517                         // Get all of the page content and link. 
    518                         $full_page = get_extended($page->post_content); 
    519                         $link = post_permalink($page->ID); 
    520  
    521                         // Get info the page parent if there is one. 
    522                         $parent_title = ""; 
    523                         if ( !empty($page->post_parent) ) { 
    524                                 $parent = get_page($page->post_parent); 
    525                                 $parent_title = $parent->post_title; 
    526                         } 
    527  
    528                         // Determine comment and ping settings. 
    529                         $allow_comments = comments_open($page->ID) ? 1 : 0; 
    530                         $allow_pings = pings_open($page->ID) ? 1 : 0; 
    531  
    532                         // Format page date. 
    533                         $page_date = mysql2date("Ymd\TH:i:s", $page->post_date, false); 
    534                         $page_date_gmt = mysql2date("Ymd\TH:i:s", $page->post_date_gmt, false); 
    535  
    536                         // For drafts use the GMT version of the date 
    537                         if ( $page->post_status == 'draft' ) 
    538                                 $page_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $page->post_date ), 'Ymd\TH:i:s' ); 
    539  
    540                         // Pull the categories info together. 
    541                         $categories = array(); 
    542                         foreach ( wp_get_post_categories($page->ID) as $cat_id ) { 
    543                                 $categories[] = get_cat_name($cat_id); 
    544                         } 
    545  
    546                         // Get the author info. 
    547                         $author = get_userdata($page->post_author); 
    548  
    549                         $page_template = get_post_meta( $page->ID, '_wp_page_template', true ); 
    550                         if ( empty( $page_template ) ) 
    551                                 $page_template = 'default'; 
    552  
    553                         $page_struct = array( 
    554                                 "dateCreated"                   => new IXR_Date($page_date), 
    555                                 "userid"                                => $page->post_author, 
    556                                 "page_id"                               => $page->ID, 
    557                                 "page_status"                   => $page->post_status, 
    558                                 "description"                   => $full_page["main"], 
    559                                 "title"                                 => $page->post_title, 
    560                                 "link"                                  => $link, 
    561                                 "permaLink"                             => $link, 
    562                                 "categories"                    => $categories, 
    563                                 "excerpt"                               => $page->post_excerpt, 
    564                                 "text_more"                             => $full_page["extended"], 
    565                                 "mt_allow_comments"             => $allow_comments, 
    566                                 "mt_allow_pings"                => $allow_pings, 
    567                                 "wp_slug"                               => $page->post_name, 
    568                                 "wp_password"                   => $page->post_password, 
    569                                 "wp_author"                             => $author->display_name, 
    570                                 "wp_page_parent_id"             => $page->post_parent, 
    571                                 "wp_page_parent_title"  => $parent_title, 
    572                                 "wp_page_order"                 => $page->menu_order, 
    573                                 "wp_author_id"                  => $author->ID, 
    574                                 "wp_author_display_name"        => $author->display_name, 
    575                                 "date_created_gmt"              => new IXR_Date($page_date_gmt), 
    576                                 "custom_fields"                 => $this->get_custom_fields($page_id), 
    577                                 "wp_page_template"              => $page_template 
    578                         ); 
    579  
    580                         return($page_struct); 
    581                 } 
    582                 // If the page doesn't exist indicate that. 
    583                 else { 
    584                         return(new IXR_Error(404, __("Sorry, no such page."))); 
    585                 } 
    586         } 
    587  
    588         /** 
    589          * Retrieve Pages. 
    590          * 
    591          * @since 2.2.0 
    592          * 
    593          * @param array $args Method parameters. 
    594          * @return array 
    595          */ 
    596         function wp_getPages($args) { 
    597                 $this->escape($args); 
    598  
    599                 $blog_id        = (int) $args[0]; 
    600                 $username       = $args[1]; 
    601                 $password       = $args[2]; 
    602                 $num_pages      = isset($args[3]) ? (int) $args[3] : 10; 
    603  
    604                 if ( !$user = $this->login($username, $password) ) 
    605                         return $this->error; 
    606  
    607                 if ( !current_user_can( 'edit_pages' ) ) 
    608                         return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) ); 
    609  
    610                 do_action('xmlrpc_call', 'wp.getPages'); 
    611  
    612                 $pages = get_posts( array('post_type' => 'page', 'post_status' => 'any', 'numberposts' => $num_pages) ); 
    613                 $num_pages = count($pages); 
    614  
    615                 // If we have pages, put together their info. 
    616                 if ( $num_pages >= 1 ) { 
    617                         $pages_struct = array(); 
    618  
    619                         for ( $i = 0; $i < $num_pages; $i++ ) { 
    620                                 $page = wp_xmlrpc_server::wp_getPage(array( 
    621                                         $blog_id, $pages[$i]->ID, $username, $password 
    622                                 )); 
    623                                 $pages_struct[] = $page; 
    624                         } 
    625  
    626                         return($pages_struct); 
    627                 } 
    628                 // If no pages were found return an error. 
    629                 else { 
    630                         return(array()); 
    631                 } 
    632         } 
    633  
    634         /** 
    635          * Create new page. 
    636          * 
    637          * @since 2.2.0 
    638          * 
    639          * @param array $args Method parameters. 
    640          * @return unknown 
    641          */ 
    642         function wp_newPage($args) { 
    643                 // Items not escaped here will be escaped in newPost. 
    644                 $username       = $this->escape($args[1]); 
    645                 $password       = $this->escape($args[2]); 
    646                 $page           = $args[3]; 
    647                 $publish        = $args[4]; 
    648  
    649                 if ( !$user = $this->login($username, $password) ) 
    650                         return $this->error; 
    651  
    652                 do_action('xmlrpc_call', 'wp.newPage'); 
    653  
    654                 // Make sure the user is allowed to add new pages. 
    655                 if ( !current_user_can("publish_pages") ) 
    656                         return(new IXR_Error(401, __("Sorry, you cannot add new pages."))); 
    657  
    658                 // Mark this as content for a page. 
    659                 $args[3]["post_type"] = "page"; 
    660  
    661                 // Let mw_newPost do all of the heavy lifting. 
    662                 return($this->mw_newPost($args)); 
    663         } 
    664  
    665         /** 
    666          * Delete page. 
    667          * 
    668          * @since 2.2.0 
    669          * 
    670          * @param array $args Method parameters. 
    671          * @return bool True, if success. 
    672          */ 
    673         function wp_deletePage($args) { 
    674                 $this->escape($args); 
    675  
    676                 $blog_id        = (int) $args[0]; 
    677                 $username       = $args[1]; 
    678                 $password       = $args[2]; 
    679                 $page_id        = (int) $args[3]; 
    680  
    681                 if ( !$user = $this->login($username, $password) ) 
    682                         return $this->error; 
    683  
    684                 do_action('xmlrpc_call', 'wp.deletePage'); 
    685  
    686                 // Get the current page based on the page_id and 
    687                 // make sure it is a page and not a post. 
    688                 $actual_page = wp_get_single_post($page_id, ARRAY_A); 
    689                 if ( !$actual_page || ($actual_page["post_type"] != "page") ) 
    690                         return(new IXR_Error(404, __("Sorry, no such page."))); 
    691  
    692                 // Make sure the user can delete pages. 
    693                 if ( !current_user_can("delete_page", $page_id) ) 
    694                         return(new IXR_Error(401, __("Sorry, you do not have the right to delete this page."))); 
    695  
    696                 // Attempt to delete the page. 
    697                 $result = wp_delete_post($page_id); 
    698                 if ( !$result ) 
    699                         return(new IXR_Error(500, __("Failed to delete the page."))); 
    700  
    701                 return(true); 
    702         } 
    703  
    704         /** 
    705          * Edit page. 
    706          * 
    707          * @since 2.2.0 
    708          * 
    709          * @param array $args Method parameters. 
    710          * @return unknown 
    711          */ 
    712         function wp_editPage($args) { 
    713                 // Items not escaped here will be escaped in editPost. 
    714                 $blog_id        = (int) $args[0]; 
    715                 $page_id        = (int) $this->escape($args[1]); 
    716                 $username       = $this->escape($args[2]); 
    717                 $password       = $this->escape($args[3]); 
    718                 $content        = $args[4]; 
    719                 $publish        = $args[5]; 
    720  
    721                 if ( !$user = $this->login($username, $password) ) 
    722                         return $this->error; 
    723  
    724                 do_action('xmlrpc_call', 'wp.editPage'); 
    725  
    726                 // Get the page data and make sure it is a page. 
    727                 $actual_page = wp_get_single_post($page_id, ARRAY_A); 
    728                 if ( !$actual_page || ($actual_page["post_type"] != "page") ) 
    729                         return(new IXR_Error(404, __("Sorry, no such page."))); 
    730  
    731                 // Make sure the user is allowed to edit pages. 
    732                 if ( !current_user_can("edit_page", $page_id) ) 
    733                         return(new IXR_Error(401, __("Sorry, you do not have the right to edit this page."))); 
    734  
    735                 // Mark this as content for a page. 
    736                 $content["post_type"] = "page"; 
    737  
    738                 // Arrange args in the way mw_editPost understands. 
    739                 $args = array( 
    740                         $page_id, 
    741                         $username, 
    742                         $password, 
    743                         $content, 
    744                         $publish 
    745                 ); 
    746  
    747                 // Let mw_editPost do all of the heavy lifting. 
    748                 return($this->mw_editPost($args)); 
    749         } 
    750  
    751         /** 
    752          * Retrieve page list. 
    753          * 
    754          * @since 2.2.0 
    755          * 
    756          * @param array $args Method parameters. 
    757          * @return unknown 
    758          */ 
    759         function wp_getPageList($args) { 
    760                 global $wpdb; 
    761  
    762                 $this->escape($args); 
    763  
    764                 $blog_id                                = (int) $args[0]; 
    765                 $username                               = $args[1]; 
    766                 $password                               = $args[2]; 
    767  
    768                 if ( !$user = $this->login($username, $password) ) 
    769                         return $this->error; 
    770  
    771                 if ( !current_user_can( 'edit_pages' ) ) 
    772                         return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) ); 
    773  
    774                 do_action('xmlrpc_call', 'wp.getPageList'); 
    775  
    776                 // Get list of pages ids and titles 
    777                 $page_list = $wpdb->get_results(" 
    778                         SELECT ID page_id, 
    779                                 post_title page_title, 
    780                                 post_parent page_parent_id, 
    781                                 post_date_gmt, 
    782                                 post_date, 
    783                                 post_status 
    784                         FROM {$wpdb->posts} 
    785                         WHERE post_type = 'page' 
    786                         ORDER BY ID 
    787                 "); 
    788  
    789                 // The date needs to be formated properly. 
    790                 $num_pages = count($page_list); 
    791                 for ( $i = 0; $i < $num_pages; $i++ ) { 
    792                         $post_date = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date, false); 
    793                         $post_date_gmt = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date_gmt, false); 
    794  
    795                         $page_list[$i]->dateCreated = new IXR_Date($post_date); 
    796                         $page_list[$i]->date_created_gmt = new IXR_Date($post_date_gmt); 
    797  
    798                         // For drafts use the GMT version of the date 
    799                         if ( $page_list[$i]->post_status == 'draft' ) { 
    800                                 $page_list[$i]->date_created_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $page_list[$i]->post_date ), 'Ymd\TH:i:s' ); 
    801                                 $page_list[$i]->date_created_gmt = new IXR_Date( $page_list[$i]->date_created_gmt ); 
    802                         } 
    803  
    804                         unset($page_list[$i]->post_date_gmt); 
    805                         unset($page_list[$i]->post_date); 
    806                         unset($page_list[$i]->post_status); 
    807                 } 
    808  
    809                 return($page_list); 
    810         } 
    811  
    812         /** 
    813          * Retrieve authors list. 
    814          * 
    815          * @since 2.2.0 
    816          * 
    817          * @param array $args Method parameters. 
    818          * @return array 
    819          */ 
    820         function wp_getAuthors($args) { 
    821  
    822                 $this->escape($args); 
    823  
    824                 $blog_id        = (int) $args[0]; 
    825                 $username       = $args[1]; 
    826                 $password       = $args[2]; 
    827  
    828                 if ( !$user = $this->login($username, $password) ) 
    829                         return $this->error; 
    830  
    831                 if ( !current_user_can("edit_posts") ) 
    832                         return(new IXR_Error(401, __("Sorry, you cannot edit posts on this site."))); 
    833  
    834                 do_action('xmlrpc_call', 'wp.getAuthors'); 
    835  
    836                 $authors = array(); 
    837                 foreach ( get_users() as $user_id => $user_object ) { 
    838                         $authors[] = array( 
    839                                 "user_id"       => $user_id, 
    840                                 "user_login"    => $user_object->user_login, 
    841                                 "display_name"  => $user_object->display_name 
    842                         ); 
    843                 } 
    844  
    845                 return $authors; 
    846         } 
    847  
    848         /** 
    849          * Get list of all tags 
    850          * 
    851          * @since 2.7 
    852          * 
    853          * @param array $args Method parameters. 
    854          * @return array 
    855          */ 
    856         function wp_getTags( $args ) { 
    857                 $this->escape( $args ); 
    858  
    859                 $blog_id                = (int) $args[0]; 
    860                 $username               = $args[1]; 
    861                 $password               = $args[2]; 
    862  
    863                 if ( !$user = $this->login($username, $password) ) 
    864                         return $this->error; 
    865  
    866                 if ( !current_user_can( 'edit_posts' ) ) 
    867                         return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view tags.' ) ); 
    868  
    869                 do_action( 'xmlrpc_call', 'wp.getKeywords' ); 
    870  
    871                 $tags = array( ); 
    872  
    873                 if ( $all_tags = get_tags() ) { 
    874                         foreach( (array) $all_tags as $tag ) { 
    875                                 $struct['tag_id']                       = $tag->term_id; 
    876                                 $struct['name']                         = $tag->name; 
    877                                 $struct['count']                        = $tag->count; 
    878                                 $struct['slug']                         = $tag->slug; 
    879                                 $struct['html_url']                     = esc_html( get_tag_link( $tag->term_id ) ); 
    880                                 $struct['rss_url']                      = esc_html( get_tag_feed_link( $tag->term_id ) ); 
    881  
    882                                 $tags[] = $struct; 
    883                         } 
    884                 } 
    885  
    886                 return $tags; 
    887         } 
    888  
    889         /** 
    890          * Create new category. 
    891          * 
    892          * @since 2.2.0 
    893          * 
    894          * @param array $args Method parameters. 
    895          * @return int Category ID. 
    896          */ 
    897         function wp_newCategory($args) { 
    898                 $this->escape($args); 
    899  
    900                 $blog_id                                = (int) $args[0]; 
    901                 $username                               = $args[1]; 
    902                 $password                               = $args[2]; 
    903                 $category                               = $args[3]; 
    904  
    905                 if ( !$user = $this->login($username, $password) ) 
    906                         return $this->error; 
    907  
    908                 do_action('xmlrpc_call', 'wp.newCategory'); 
    909  
    910                 // Make sure the user is allowed to add a category. 
    911                 if ( !current_user_can("manage_categories") ) 
    912                         return(new IXR_Error(401, __("Sorry, you do not have the right to add a category."))); 
    913  
    914                 // If no slug was provided make it empty so that 
    915                 // WordPress will generate one. 
    916                 if ( empty($category["slug"]) ) 
    917                         $category["slug"] = ""; 
    918  
    919                 // If no parent_id was provided make it empty 
    920                 // so that it will be a top level page (no parent). 
    921                 if ( !isset($category["parent_id"]) ) 
    922                         $category["parent_id"] = ""; 
    923  
    924                 // If no description was provided make it empty. 
    925                 if ( empty($category["description"]) ) 
    926                         $category["description"] = ""; 
    927  
    928                 $new_category = array( 
    929                         "cat_name"                              => $category["name"], 
    930                         "category_nicename"             => $category["slug"], 
    931                         "category_parent"               => $category["parent_id"], 
    932                         "category_description"  => $category["description"] 
    933                 ); 
    934  
    935                 $cat_id = wp_insert_category($new_category, true); 
    936                 if ( is_wp_error( $cat_id ) ) { 
    937                         if ( 'term_exists' == $cat_id->get_error_code() ) 
    938                                 return (int) $cat_id->get_error_data(); 
    939                         else 
    940                                 return(new IXR_Error(500, __("Sorry, the new category failed."))); 
    941                 } elseif ( ! $cat_id ) { 
    942                         return(new IXR_Error(500, __("Sorry, the new category failed."))); 
    943                 } 
    944  
    945                 return($cat_id); 
    946         } 
    947  
    948         /** 
    949          * Remove category. 
    950          * 
    951          * @since 2.5.0 
    952          * 
    953          * @param array $args Method parameters. 
    954          * @return mixed See {@link wp_delete_category()} for return info. 
    955          */ 
    956         function wp_deleteCategory($args) { 
    957                 $this->escape($args); 
    958  
    959                 $blog_id                = (int) $args[0]; 
    960                 $username               = $args[1]; 
    961                 $password               = $args[2]; 
    962                 $category_id    = (int) $args[3]; 
    963  
    964                 if ( !$user = $this->login($username, $password) ) 
    965                         return $this->error; 
    966  
    967                 do_action('xmlrpc_call', 'wp.deleteCategory'); 
    968  
    969                 if ( !current_user_can("manage_categories") ) 
    970                         return new IXR_Error( 401, __( "Sorry, you do not have the right to delete a category." ) ); 
    971  
    972                 return wp_delete_category( $category_id ); 
    973         } 
    974  
    975         /** 
    976          * Retrieve category list. 
    977          * 
    978          * @since 2.2.0 
    979          * 
    980          * @param array $args Method parameters. 
    981          * @return array 
    982          */ 
    983         function wp_suggestCategories($args) { 
    984                 $this->escape($args); 
    985  
    986                 $blog_id                                = (int) $args[0]; 
    987                 $username                               = $args[1]; 
    988                 $password                               = $args[2]; 
    989                 $category                               = $args[3]; 
    990                 $max_results                    = (int) $args[4]; 
    991  
    992                 if ( !$user = $this->login($username, $password) ) 
    993                         return $this->error; 
    994  
    995                 if ( !current_user_can( 'edit_posts' ) ) 
    996                         return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts to this site in order to view categories.' ) ); 
    997  
    998                 do_action('xmlrpc_call', 'wp.suggestCategories'); 
    999  
    1000                 $category_suggestions = array(); 
    1001                 $args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category); 
    1002                 foreach ( (array) get_categories($args) as $cat ) { 
    1003                         $category_suggestions[] = array( 
    1004                                 "category_id"   => $cat->cat_ID, 
    1005                                 "category_name" => $cat->cat_name 
    1006                         ); 
    1007                 } 
    1008  
    1009                 return($category_suggestions); 
    1010         } 
    1011  
    1012         /** 
    1013          * Retrieve comment. 
    1014          * 
    1015          * @since 2.7.0 
    1016          * 
    1017          * @param array $args Method parameters. 
    1018          * @return array 
    1019          */ 
    1020         function wp_getComment($args) { 
    1021                 $this->escape($args); 
    1022  
    1023                 $blog_id        = (int) $args[0]; 
    1024                 $username       = $args[1]; 
    1025                 $password       = $args[2]; 
    1026                 $comment_id     = (int) $args[3]; 
    1027  
    1028                 if ( !$user = $this->login($username, $password) ) 
    1029                         return $this->error; 
    1030  
    1031                 if ( !current_user_can( 'moderate_comments' ) ) 
    1032                         return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) ); 
    1033  
    1034                 do_action('xmlrpc_call', 'wp.getComment'); 
    1035  
    1036                 if ( ! $comment = get_comment($comment_id) ) 
    1037                         return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); 
    1038  
    1039                 // Format page date. 
    1040                 $comment_date = mysql2date("Ymd\TH:i:s", $comment->comment_date, false); 
    1041                 $comment_date_gmt = mysql2date("Ymd\TH:i:s", $comment->comment_date_gmt, false); 
    1042  
    1043                 if ( '0' == $comment->comment_approved ) 
    1044                         $comment_status = 'hold'; 
    1045                 else if ( 'spam' == $comment->comment_approved ) 
    1046                         $comment_status = 'spam'; 
    1047                 else if ( '1' == $comment->comment_approved ) 
    1048                         $comment_status = 'approve'; 
    1049                 else 
    1050                         $comment_status = $comment->comment_approved; 
    1051  
    1052                 $link = get_comment_link($comment); 
    1053  
    1054                 $comment_struct = array( 
    1055                         "date_created_gmt"              => new IXR_Date($comment_date_gmt), 
    1056                         "user_id"                               => $comment->user_id, 
    1057                         "comment_id"                    => $comment->comment_ID, 
    1058                         "parent"                                => $comment->comment_parent, 
    1059                         "status"                                => $comment_status, 
    1060                         "content"                               => $comment->comment_content, 
    1061                         "link"                                  => $link, 
    1062                         "post_id"                               => $comment->comment_post_ID, 
    1063                         "post_title"                    => get_the_title($comment->comment_post_ID), 
    1064                         "author"                                => $comment->comment_author, 
    1065                         "author_url"                    => $comment->comment_author_url, 
    1066                         "author_email"                  => $comment->comment_author_email, 
    1067                         "author_ip"                             => $comment->comment_author_IP, 
    1068                         "type"                                  => $comment->comment_type, 
    1069                 ); 
    1070  
    1071                 return $comment_struct; 
    1072         } 
    1073  
    1074         /** 
    1075          * Retrieve comments. 
    1076          * 
    1077          * @since 2.7.0 
    1078          * 
    1079          * @param array $args Method parameters. 
    1080          * @return array 
    1081          */ 
    1082         function wp_getComments($args) { 
    1083                 $raw_args = $args; 
    1084                 $this->escape($args); 
    1085  
    1086                 $blog_id        = (int) $args[0]; 
    1087                 $username       = $args[1]; 
    1088                 $password       = $args[2]; 
    1089                 $struct         = $args[3]; 
    1090  
    1091                 if ( !$user = $this->login($username, $password) ) 
    1092                         return $this->error; 
    1093  
    1094                 if ( !current_user_can( 'moderate_comments' ) ) 
    1095                         return new IXR_Error( 401, __( 'Sorry, you cannot edit comments.' ) ); 
    1096  
    1097                 do_action('xmlrpc_call', 'wp.getComments'); 
    1098  
    1099                 if ( isset($struct['status']) ) 
    1100                         $status = $struct['status']; 
    1101                 else 
    1102                         $status = ''; 
    1103  
    1104                 $post_id = ''; 
    1105                 if ( isset($struct['post_id']) ) 
    1106                         $post_id = absint($struct['post_id']); 
    1107  
    1108                 $offset = 0; 
    1109                 if ( isset($struct['offset']) ) 
    1110                         $offset = absint($struct['offset']); 
    1111  
    1112                 $number = 10; 
    1113                 if ( isset($struct['number']) ) 
    1114                         $number = absint($struct['number']); 
    1115  
    1116                 $comments = get_comments( array('status' => $status, 'post_id' => $post_id, 'offset' => $offset, 'number' => $number ) ); 
    1117                 $num_comments = count($comments); 
    1118  
    1119                 if ( ! $num_comments ) 
    1120                         return array(); 
    1121  
    1122                 $comments_struct = array(); 
    1123  
    1124                 for ( $i = 0; $i < $num_comments; $i++ ) { 
    1125                         $comment = wp_xmlrpc_server::wp_getComment(array( 
    1126                                 $raw_args[0], $raw_args[1], $raw_args[2], $comments[$i]->comment_ID, 
    1127                         )); 
    1128                         $comments_struct[] = $comment; 
    1129                 } 
    1130  
    1131                 return $comments_struct; 
    1132         } 
    1133  
    1134         /** 
    1135          * Remove comment. 
    1136          * 
    1137          * @since 2.7.0 
    1138          * 
    1139          * @param array $args Method parameters. 
    1140          * @return mixed {@link wp_delete_comment()} 
    1141          */ 
    1142         function wp_deleteComment($args) { 
    1143                 $this->escape($args); 
    1144  
    1145                 $blog_id        = (int) $args[0]; 
    1146                 $username       = $args[1]; 
    1147                 $password       = $args[2]; 
    1148                 $comment_ID     = (int) $args[3]; 
    1149  
    1150                 if ( !$user = $this->login($username, $password) ) 
    1151                         return $this->error; 
    1152  
    1153                 if ( !current_user_can( 'moderate_comments' ) ) 
    1154                         return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) ); 
    1155  
    1156                 do_action('xmlrpc_call', 'wp.deleteComment'); 
    1157  
    1158                 if ( ! get_comment($comment_ID) ) 
    1159                         return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); 
    1160  
    1161                 return wp_delete_comment($comment_ID); 
    1162         } 
    1163  
    1164         /** 
    1165          * Edit comment. 
    1166          * 
    1167          * @since 2.7.0 
    1168          * 
    1169          * @param array $args Method parameters. 
    1170          * @return bool True, on success. 
    1171          */ 
    1172         function wp_editComment($args) { 
    1173                 $this->escape($args); 
    1174  
    1175                 $blog_id        = (int) $args[0]; 
    1176                 $username       = $args[1]; 
    1177                 $password       = $args[2]; 
    1178                 $comment_ID     = (int) $args[3]; 
    1179                 $content_struct = $args[4]; 
    1180  
    1181                 if ( !$user = $this->login($username, $password) ) 
    1182                         return $this->error; 
    1183  
    1184                 if ( !current_user_can( 'moderate_comments' ) ) 
    1185                         return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) ); 
    1186  
    1187                 do_action('xmlrpc_call', 'wp.editComment'); 
    1188  
    1189                 if ( ! get_comment($comment_ID) ) 
    1190                         return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); 
    1191  
    1192                 if ( isset($content_struct['status']) ) { 
    1193                         $statuses = get_comment_statuses(); 
    1194                         $statuses = array_keys($statuses); 
    1195  
    1196                         if ( ! in_array($content_struct['status'], $statuses) ) 
    1197                                 return new IXR_Error( 401, __( 'Invalid comment status.' ) ); 
    1198                         $comment_approved = $content_struct['status']; 
    1199                 } 
    1200  
    1201                 // Do some timestamp voodoo 
    1202                 if ( !empty( $content_struct['date_created_gmt'] ) ) { 
    1203                         $dateCreated = str_replace( 'Z', '', $content_struct['date_created_gmt']->getIso() ) . 'Z'; // We know this is supposed to be GMT, so we're going to slap that Z on there by force 
    1204                         $comment_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); 
    1205                         $comment_date_gmt = iso8601_to_datetime($dateCreated, GMT); 
    1206                 } 
    1207  
    1208                 if ( isset($content_struct['content']) ) 
    1209                         $comment_content = $content_struct['content']; 
    1210  
    1211                 if ( isset($content_struct['author']) ) 
    1212                         $comment_author = $content_struct['author']; 
    1213  
    1214                 if ( isset($content_struct['author_url']) ) 
    1215                         $comment_author_url = $content_struct['author_url']; 
    1216  
    1217                 if ( isset($content_struct['author_email']) ) 
    1218                         $comment_author_email = $content_struct['author_email']; 
    1219  
    1220                 // We've got all the data -- post it: 
    1221                 $comment = compact('comment_ID', 'comment_content', 'comment_approved', 'comment_date', 'comment_date_gmt', 'comment_author', 'comment_author_email', 'comment_author_url'); 
    1222  
    1223                 $result = wp_update_comment($comment); 
    1224                 if ( is_wp_error( $result ) ) 
    1225                         return new IXR_Error(500, $result->get_error_message()); 
    1226  
    1227                 if ( !$result ) 
    1228                         return new IXR_Error(500, __('Sorry, the comment could not be edited. Something wrong happened.')); 
    1229  
    1230                 return true; 
    1231         } 
    1232  
    1233         /** 
    1234          * Create new comment. 
    1235          * 
    1236          * @since 2.7.0 
    1237          * 
    1238          * @param array $args Method parameters. 
    1239          * @return mixed {@link wp_new_comment()} 
    1240          */ 
    1241         function wp_newComment($args) { 
    1242                 global $wpdb; 
    1243  
    1244                 $this->escape($args); 
    1245  
    1246                 $blog_id        = (int) $args[0]; 
    1247                 $username       = $args[1]; 
    1248                 $password       = $args[2]; 
    1249                 $post           = $args[3]; 
    1250                 $content_struct = $args[4]; 
    1251  
    1252                 $allow_anon = apply_filters('xmlrpc_allow_anonymous_comments', false); 
    1253  
    1254                 $user = $this->login($username, $password); 
    1255  
    1256                 if ( !$user ) { 
    1257                         $logged_in = false; 
    1258                         if ( $allow_anon && get_option('comment_registration') ) 
    1259                                 return new IXR_Error( 403, __( 'You must be registered to comment' ) ); 
    1260                         else if ( !$allow_anon ) 
    1261                                 return $this->error; 
    1262                 } else { 
    1263                         $logged_in = true; 
    1264                 } 
    1265  
    1266                 if ( is_numeric($post) ) 
    1267                         $post_id = absint($post); 
    1268                 else 
    1269                         $post_id = url_to_postid($post); 
    1270  
    1271                 if ( ! $post_id ) 
    1272                         return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 
    1273  
    1274                 if ( ! get_post($post_id) ) 
    1275                         return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 
    1276  
    1277                 $comment['comment_post_ID'] = $post_id; 
    1278  
    1279                 if ( $logged_in ) { 
    1280                         $comment['comment_author'] = $wpdb->escape( $user->display_name ); 
    1281                         $comment['comment_author_email'] = $wpdb->escape( $user->user_email ); 
    1282                         $comment['comment_author_url'] = $wpdb->escape( $user->user_url ); 
    1283                         $comment['user_ID'] = $user->ID; 
    1284                 } else { 
    1285                         $comment['comment_author'] = ''; 
    1286                         if ( isset($content_struct['author']) ) 
    1287                                 $comment['comment_author'] = $content_struct['author']; 
    1288  
    1289                         $comment['comment_author_email'] = ''; 
    1290                         if ( isset($content_struct['author_email']) ) 
    1291                                 $comment['comment_author_email'] = $content_struct['author_email']; 
    1292  
    1293                         $comment['comment_author_url'] = ''; 
    1294                         if ( isset($content_struct['author_url']) ) 
    1295                                 $comment['comment_author_url'] = $content_struct['author_url']; 
    1296  
    1297                         $comment['user_ID'] = 0; 
    1298  
    1299                         if ( get_option('require_name_email') ) { 
    1300                                 if ( 6 > strlen($comment['comment_author_email']) || '' == $comment['comment_author'] ) 
    1301                                         return new IXR_Error( 403, __( 'Comment author name and email are required' ) ); 
    1302                                 elseif ( !is_email($comment['comment_author_email']) ) 
    1303                                         return new IXR_Error( 403, __( 'A valid email address is required' ) ); 
    1304                         } 
    1305                 } 
    1306  
    1307                 $comment['comment_parent'] = isset($content_struct['comment_parent']) ? absint($content_struct['comment_parent']) : 0; 
    1308  
    1309                 $comment['comment_content'] = $content_struct['content']; 
    1310  
    1311                 do_action('xmlrpc_call', 'wp.newComment'); 
    1312  
    1313                 return wp_new_comment($comment); 
    1314         } 
    1315  
    1316         /** 
    1317          * Retrieve all of the comment status. 
    1318          * 
    1319          * @since 2.7.0 
    1320          * 
    1321          * @param array $args Method parameters. 
    1322          * @return array 
    1323          */ 
    1324         function wp_getCommentStatusList($args) { 
    1325                 $this->escape( $args ); 
    1326  
    1327                 $blog_id        = (int) $args[0]; 
    1328                 $username       = $args[1]; 
    1329                 $password       = $args[2]; 
    1330  
    1331                 if ( !$user = $this->login($username, $password) ) 
    1332                         return $this->error; 
    1333  
    1334                 if ( !current_user_can( 'moderate_comments' ) ) 
    1335                         return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) ); 
    1336  
    1337                 do_action('xmlrpc_call', 'wp.getCommentStatusList'); 
    1338  
    1339                 return get_comment_statuses( ); 
    1340         } 
    1341  
    1342         /** 
    1343          * Retrieve comment count. 
    1344          * 
    1345          * @since 2.5.0 
    1346          * 
    1347          * @param array $args Method parameters. 
    1348          * @return array 
    1349          */ 
    1350         function wp_getCommentCount( $args ) { 
    1351                 $this->escape($args); 
    1352  
    1353                 $blog_id        = (int) $args[0]; 
    1354                 $username       = $args[1]; 
    1355                 $password       = $args[2]; 
    1356                 $post_id        = (int) $args[3]; 
    1357  
    1358                 if ( !$user = $this->login($username, $password) ) 
    1359                         return $this->error; 
    1360  
    1361                 if ( !current_user_can( 'edit_posts' ) ) 
    1362                         return new IXR_Error( 403, __( 'You are not allowed access to details about comments.' ) ); 
    1363  
    1364                 do_action('xmlrpc_call', 'wp.getCommentCount'); 
    1365  
    1366                 $count = wp_count_comments( $post_id ); 
    1367                 return array( 
    1368                         "approved" => $count->approved, 
    1369                         "awaiting_moderation" => $count->moderated, 
    1370                         "spam" => $count->spam, 
    1371                         "total_comments" => $count->total_comments 
    1372                 ); 
    1373         } 
    1374  
    1375         /** 
    1376          * Retrieve post statuses. 
    1377          * 
    1378          * @since 2.5.0 
    1379          * 
    1380          * @param array $args Method parameters. 
    1381          * @return array 
    1382          */ 
    1383         function wp_getPostStatusList( $args ) { 
    1384                 $this->escape( $args ); 
    1385  
    1386                 $blog_id        = (int) $args[0]; 
    1387                 $username       = $args[1]; 
    1388                 $password       = $args[2]; 
    1389  
    1390                 if ( !$user = $this->login($username, $password) ) 
    1391                         return $this->error; 
    1392  
    1393                 if ( !current_user_can( 'edit_posts' ) ) 
    1394                         return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) ); 
    1395  
    1396                 do_action('xmlrpc_call', 'wp.getPostStatusList'); 
    1397  
    1398                 return get_post_statuses( ); 
    1399         } 
    1400  
    1401         /** 
    1402          * Retrieve page statuses. 
    1403          * 
    1404          * @since 2.5.0 
    1405          * 
    1406          * @param array $args Method parameters. 
    1407          * @return array 
    1408          */ 
    1409         function wp_getPageStatusList( $args ) { 
    1410                 $this->escape( $args ); 
    1411  
    1412                 $blog_id        = (int) $args[0]; 
    1413                 $username       = $args[1]; 
    1414                 $password       = $args[2]; 
    1415  
    1416                 if ( !$user = $this->login($username, $password) ) 
    1417                         return $this->error; 
    1418  
    1419                 if ( !current_user_can( 'edit_posts' ) ) 
    1420                         return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) ); 
    1421  
    1422                 do_action('xmlrpc_call', 'wp.getPageStatusList'); 
    1423  
    1424                 return get_page_statuses( ); 
    1425         } 
    1426  
    1427         /** 
    1428          * Retrieve page templates. 
    1429          * 
    1430          * @since 2.6.0 
    1431          * 
    1432          * @param array $args Method parameters. 
    1433          * @return array 
    1434          */ 
    1435         function wp_getPageTemplates( $args ) { 
    1436                 $this->escape( $args ); 
    1437  
    1438                 $blog_id        = (int) $args[0]; 
    1439                 $username       = $args[1]; 
    1440                 $password       = $args[2]; 
    1441  
    1442                 if ( !$user = $this->login($username, $password) ) 
    1443                         return $this->error; 
    1444  
    1445                 if ( !current_user_can( 'edit_pages' ) ) 
    1446                         return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) ); 
    1447  
    1448                 $templates = get_page_templates( ); 
    1449                 $templates['Default'] = 'default'; 
    1450  
    1451                 return $templates; 
    1452         } 
    1453  
    1454         /** 
    1455          * Retrieve blog options. 
    1456          * 
    1457          * @since 2.6.0 
    1458          * 
    1459          * @param array $args Method parameters. 
    1460          * @return array 
    1461          */ 
    1462         function wp_getOptions( $args ) { 
    1463                 $this->escape( $args ); 
    1464  
    1465                 $blog_id        = (int) $args[0]; 
    1466                 $username       = $args[1]; 
    1467                 $password       = $args[2]; 
    1468                 $options        = (array) $args[3]; 
    1469  
    1470                 if ( !$user = $this->login($username, $password) ) 
    1471                         return $this->error; 
    1472  
    1473                 // If no specific options where asked for, return all of them 
    1474                 if ( count( $options ) == 0 ) 
    1475                         $options = array_keys($this->blog_options); 
    1476  
    1477                 return $this->_getOptions($options); 
    1478         } 
    1479  
    1480         /** 
    1481          * Retrieve blog options value from list. 
    1482          * 
    1483          * @since 2.6.0 
    1484          * 
    1485          * @param array $options Options to retrieve. 
    1486          * @return array 
    1487          */ 
    1488         function _getOptions($options) { 
    1489                 $data = array( ); 
    1490                 foreach ( $options as $option ) { 
    1491                         if ( array_key_exists( $option, $this->blog_options ) ) { 
    1492                                 $data[$option] = $this->blog_options[$option]; 
    1493                                 //Is the value static or dynamic? 
    1494                                 if ( isset( $data[$option]['option'] ) ) { 
    1495                                         $data[$option]['value'] = get_option( $data[$option]['option'] ); 
    1496                                         unset($data[$option]['option']); 
    1497                                 } 
    1498                         } 
    1499                 } 
    1500  
    1501                 return $data; 
    1502         } 
    1503  
    1504         /** 
    1505          * Update blog options. 
    1506          * 
    1507          * @since 2.6.0 
    1508          * 
    1509          * @param array $args Method parameters. 
    1510          * @return unknown 
    1511          */ 
    1512         function wp_setOptions( $args ) { 
    1513                 $this->escape( $args ); 
    1514  
    1515                 $blog_id        = (int) $args[0]; 
    1516                 $username       = $args[1]; 
    1517                 $password       = $args[2]; 
    1518                 $options        = (array) $args[3]; 
    1519  
    1520                 if ( !$user = $this->login($username, $password) ) 
    1521                         return $this->error; 
    1522  
    1523                 if ( !current_user_can( 'manage_options' ) ) 
    1524                         return new IXR_Error( 403, __( 'You are not allowed to update options.' ) ); 
    1525  
    1526                 foreach ( $options as $o_name => $o_value ) { 
    1527                         $option_names[] = $o_name; 
    1528                         if ( !array_key_exists( $o_name, $this->blog_options ) ) 
    1529                                 continue; 
    1530  
    1531                         if ( $this->blog_options[$o_name]['readonly'] == true ) 
    1532                                 continue; 
    1533  
    1534                         update_option( $this->blog_options[$o_name]['option'], $o_value ); 
    1535                 } 
    1536  
    1537                 //Now return the updated values 
    1538                 return $this->_getOptions($option_names); 
    1539         } 
    1540  
    1541         /* Blogger API functions. 
    1542          * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/ 
    1543          */ 
    1544  
    1545         /** 
    1546          * Retrieve blogs that user owns. 
    1547          * 
    1548          * Will make more sense once we support multiple blogs. 
    1549          * 
    1550          * @since 1.5.0 
    1551          * 
    1552          * @param array $args Method parameters. 
    1553          * @return array 
    1554          */ 
    1555         function blogger_getUsersBlogs($args) { 
    1556                 if ( is_multisite() ) 
    1557                         return $this->_multisite_getUsersBlogs($args); 
    1558  
    1559                 $this->escape($args); 
    1560  
    1561                 $username = $args[1]; 
    1562                 $password  = $args[2]; 
    1563  
    1564                 if ( !$user = $this->login($username, $password) ) 
    1565                         return $this->error; 
    1566  
    1567                 do_action('xmlrpc_call', 'blogger.getUsersBlogs'); 
    1568  
    1569                 $is_admin = current_user_can('manage_options'); 
    1570  
    1571                 $struct = array( 
    1572                         'isAdmin'  => $is_admin, 
    1573                         'url'      => get_option('home') . '/', 
    1574                         'blogid'   => '1', 
    1575                         'blogName' => get_option('blogname'), 
    1576                         'xmlrpc'   => site_url( 'xmlrpc.php' ) 
    1577                 ); 
    1578  
    1579                 return array($struct); 
    1580         } 
    1581  
    1582         /** 
    1583          * Private function for retrieving a users blogs for multisite setups 
    1584          * 
    1585          * @access protected 
    1586          */ 
    1587         function _multisite_getUsersBlogs($args) { 
    1588                 global $current_blog; 
    1589                 $domain = $current_blog->domain; 
    1590                 $path = $current_blog->path . 'xmlrpc.php'; 
    1591                 $protocol = is_ssl() ? 'https' : 'http'; 
    1592  
    1593                 $rpc = new IXR_Client("$protocol://{$domain}{$path}"); 
    1594                 $rpc->query('wp.getUsersBlogs', $args[1], $args[2]); 
    1595                 $blogs = $rpc->getResponse(); 
    1596  
    1597                 if ( isset($blogs['faultCode']) ) 
    1598                         return new IXR_Error($blogs['faultCode'], $blogs['faultString']); 
    1599  
    1600                 if ( $_SERVER['HTTP_HOST'] == $domain && $_SERVER['REQUEST_URI'] == $path ) { 
    1601                         return $blogs; 
    1602                 } else { 
    1603                         foreach ( (array) $blogs as $blog ) { 
    1604                                 if ( strpos($blog['url'], $_SERVER['HTTP_HOST']) ) 
    1605                                         return array($blog); 
    1606                         } 
    1607                         return array(); 
    1608                 } 
    1609         } 
    1610  
    1611         /** 
    1612          * Retrieve user's data. 
    1613          * 
    1614          * Gives your client some info about you, so you don't have to. 
    1615          * 
    1616          * @since 1.5.0 
    1617          * 
    1618          * @param array $args Method parameters. 
    1619          * @return array 
    1620          */ 
    1621         function blogger_getUserInfo($args) { 
    1622  
    1623                 $this->escape($args); 
    1624  
    1625                 $username = $args[1]; 
    1626                 $password  = $args[2]; 
    1627  
    1628                 if ( !$user = $this->login($username, $password) ) 
    1629                         return $this->error; 
    1630  
    1631                 if ( !current_user_can( 'edit_posts' ) ) 
    1632                         return new IXR_Error( 401, __( 'Sorry, you do not have access to user data on this site.' ) ); 
    1633  
    1634                 do_action('xmlrpc_call', 'blogger.getUserInfo'); 
    1635  
    1636                 $struct = array( 
    1637                         'nickname'  => $user->nickname, 
    1638                         'userid'    => $user->ID, 
    1639                         'url'       => $user->user_url, 
    1640                         'lastname'  => $user->last_name, 
    1641                         'firstname' => $user->first_name 
    1642                 ); 
    1643  
    1644                 return $struct; 
    1645         } 
    1646  
    1647         /** 
    1648          * Retrieve post. 
    1649          * 
    1650          * @since 1.5.0 
    1651          * 
    1652          * @param array $args Method parameters. 
    1653          * @return array 
    1654          */ 
    1655         function blogger_getPost($args) { 
    1656  
    1657                 $this->escape($args); 
    1658  
    1659                 $post_ID    = (int) $args[1]; 
    1660                 $username = $args[2]; 
    1661                 $password  = $args[3]; 
    1662  
    1663                 if ( !$user = $this->login($username, $password) ) 
    1664                         return $this->error; 
    1665  
    1666                 if ( !current_user_can( 'edit_post', $post_ID ) ) 
    1667                         return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) ); 
    1668  
    1669                 do_action('xmlrpc_call', 'blogger.getPost'); 
    1670  
    1671                 $post_data = wp_get_single_post($post_ID, ARRAY_A); 
    1672  
    1673                 $categories = implode(',', wp_get_post_categories($post_ID)); 
    1674  
    1675                 $content  = '<title>'.stripslashes($post_data['post_title']).'</title>'; 
    1676                 $content .= '<category>'.$categories.'</category>'; 
    1677                 $content .= stripslashes($post_data['post_content']); 
    1678  
    1679                 $struct = array( 
    1680                         'userid'    => $post_data['post_author'], 
    1681                         'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'], false)), 
    1682                         'content'     => $content, 
    1683                         'postid'  => $post_data['ID'] 
    1684                 ); 
    1685  
    1686                 return $struct; 
    1687         } 
    1688  
    1689         /** 
    1690          * Retrieve list of recent posts. 
    1691          * 
    1692          * @since 1.5.0 
    1693          * 
    1694          * @param array $args Method parameters. 
    1695          * @return array 
    1696          */ 
    1697         function blogger_getRecentPosts($args) { 
    1698  
    1699                 $this->escape($args); 
    1700  
    1701                 $blog_ID    = (int) $args[1]; /* though we don't use it yet */ 
    1702                 $username = $args[2]; 
    1703                 $password  = $args[3]; 
    1704                 $num_posts  = $args[4]; 
    1705  
    1706                 if ( !$user = $this->login($username, $password) ) 
    1707                         return $this->error; 
    1708  
    1709                 do_action('xmlrpc_call', 'blogger.getRecentPosts'); 
    1710  
    1711                 $posts_list = wp_get_recent_posts($num_posts); 
    1712  
    1713                 if ( !$posts_list ) { 
    1714                         $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.')); 
    1715                         return $this->error; 
    1716                 } 
    1717  
    1718                 foreach ($posts_list as $entry) { 
    1719                         if ( !current_user_can( 'edit_post', $entry['ID'] ) ) 
    1720                                 continue; 
    1721  
    1722                         $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false); 
    1723                         $categories = implode(',', wp_get_post_categories($entry['ID'])); 
    1724  
    1725                         $content  = '<title>'.stripslashes($entry['post_title']).'</title>'; 
    1726                         $content .= '<category>'.$categories.'</category>'; 
    1727                         $content .= stripslashes($entry['post_content']); 
    1728  
    1729                         $struct[] = array( 
    1730                                 'userid' => $entry['post_author'], 
    1731                                 'dateCreated' => new IXR_Date($post_date), 
    1732                                 'content' => $content, 
    1733                                 'postid' => $entry['ID'], 
    1734                         ); 
    1735  
    1736                 } 
    1737  
    1738                 $recent_posts = array(); 
    1739                 for ( $j=0; $j<count($struct); $j++ ) { 
    1740                         array_push($recent_posts, $struct[$j]); 
    1741                 } 
    1742  
    1743                 return $recent_posts; 
    1744         } 
    1745  
    1746         /** 
    1747          * Retrieve blog_filename content. 
    1748          * 
    1749          * @since 1.5.0 
    1750          * 
    1751          * @param array $args Method parameters. 
    1752          * @return string 
    1753          */ 
    1754         function blogger_getTemplate($args) { 
    1755  
    1756                 $this->escape($args); 
    1757  
    1758                 $blog_ID    = (int) $args[1]; 
    1759                 $username = $args[2]; 
    1760                 $password  = $args[3]; 
    1761                 $template   = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */ 
    1762  
    1763                 if ( !$user = $this->login($username, $password) ) 
    1764                         return $this->error; 
    1765  
    1766                 do_action('xmlrpc_call', 'blogger.getTemplate'); 
    1767  
    1768                 if ( !current_user_can('edit_themes') ) 
    1769                         return new IXR_Error(401, __('Sorry, this user can not edit the template.')); 
    1770  
    1771                 /* warning: here we make the assumption that the blog's URL is on the same server */ 
    1772                 $filename = get_option('home') . '/'; 
    1773                 $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); 
    1774  
    1775                 $f = fopen($filename, 'r'); 
    1776                 $content = fread($f, filesize($filename)); 
    1777                 fclose($f); 
    1778  
    1779                 /* so it is actually editable with a windows/mac client */ 
    1780                 // FIXME: (or delete me) do we really want to cater to bad clients at the expense of good ones by BEEPing up their line breaks? commented.     $content = str_replace("\n", "\r\n", $content); 
    1781  
    1782                 return $content; 
    1783         } 
    1784  
    1785         /** 
    1786          * Updates the content of blog_filename. 
    1787          * 
    1788          * @since 1.5.0 
    1789          * 
    1790          * @param array $args Method parameters. 
    1791          * @return bool True when done. 
    1792          */ 
    1793         function blogger_setTemplate($args) { 
    1794  
    1795                 $this->escape($args); 
    1796  
    1797                 $blog_ID    = (int) $args[1]; 
    1798                 $username = $args[2]; 
    1799                 $password  = $args[3]; 
    1800                 $content    = $args[4]; 
    1801                 $template   = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */ 
    1802  
    1803                 if ( !$user = $this->login($username, $password) ) 
    1804                         return $this->error; 
    1805  
    1806                 do_action('xmlrpc_call', 'blogger.setTemplate'); 
    1807  
    1808                 if ( !current_user_can('edit_themes') ) 
    1809                         return new IXR_Error(401, __('Sorry, this user cannot edit the template.')); 
    1810  
    1811                 /* warning: here we make the assumption that the blog's URL is on the same server */ 
    1812                 $filename = get_option('home') . '/'; 
    1813                 $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); 
    1814  
    1815                 if ($f = fopen($filename, 'w+')) { 
    1816                         fwrite($f, $content); 
    1817                         fclose($f); 
    1818                 } else { 
    1819                         return new IXR_Error(500, __('Either the file is not writable, or something wrong happened. The file has not been updated.')); 
    1820                 } 
    1821  
    1822                 return true; 
    1823         } 
    1824  
    1825         /** 
    1826          * Create new post. 
    1827          * 
    1828          * @since 1.5.0 
    1829          * 
    1830          * @param array $args Method parameters. 
    1831          * @return int 
    1832          */ 
    1833         function blogger_newPost($args) { 
    1834  
    1835                 $this->escape($args); 
    1836  
    1837                 $blog_ID    = (int) $args[1]; /* though we don't use it yet */ 
    1838                 $username = $args[2]; 
    1839                 $password  = $args[3]; 
    1840                 $content    = $args[4]; 
    1841                 $publish    = $args[5]; 
    1842  
    1843                 if ( !$user = $this->login($username, $password) ) 
    1844                         return $this->error; 
    1845  
    1846                 do_action('xmlrpc_call', 'blogger.newPost'); 
    1847  
    1848                 $cap = ($publish) ? 'publish_posts' : 'edit_posts'; 
    1849                 if ( !current_user_can($cap) ) 
    1850                         return new IXR_Error(401, __('Sorry, you are not allowed to post on this site.')); 
    1851  
    1852                 $post_status = ($publish) ? 'publish' : 'draft'; 
    1853  
    1854                 $post_author = $user->ID; 
    1855  
    1856                 $post_title = xmlrpc_getposttitle($content); 
    1857                 $post_category = xmlrpc_getpostcategory($content); 
    1858                 $post_content = xmlrpc_removepostdata($content); 
    1859  
    1860                 $post_date = current_time('mysql'); 
    1861                 $post_date_gmt = current_time('mysql', 1); 
    1862  
    1863                 $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status'); 
    1864  
    1865                 $post_ID = wp_insert_post($post_data); 
    1866                 if ( is_wp_error( $post_ID ) ) 
    1867                         return new IXR_Error(500, $post_ID->get_error_message()); 
    1868  
    1869                 if ( !$post_ID ) 
    1870                         return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.')); 
    1871  
    1872                 $this->attach_uploads( $post_ID, $post_content ); 
    1873  
    1874                 logIO('O', "Posted ! ID: $post_ID"); 
    1875  
    1876                 return $post_ID; 
    1877         } 
    1878  
    1879         /** 
    1880          * Edit a post. 
    1881          * 
    1882          * @since 1.5.0 
    1883          * 
    1884          * @param array $args Method parameters. 
    1885          * @return bool true when done. 
    1886          */ 
    1887         function blogger_editPost($args) { 
    1888  
    1889                 $this->escape($args); 
    1890  
    1891                 $post_ID     = (int) $args[1]; 
    1892                 $username  = $args[2]; 
    1893                 $password   = $args[3]; 
    1894                 $content     = $args[4]; 
    1895                 $publish     = $args[5]; 
    1896  
    1897                 if ( !$user = $this->login($username, $password) ) 
    1898                         return $this->error; 
    1899  
    1900                 do_action('xmlrpc_call', 'blogger.editPost'); 
    1901  
    1902                 $actual_post = wp_get_single_post($post_ID,ARRAY_A); 
    1903  
    1904                 if ( !$actual_post || $actual_post['post_type'] != 'post' ) 
    1905                         return new IXR_Error(404, __('Sorry, no such post.')); 
    1906  
    1907                 $this->escape($actual_post); 
    1908  
    1909                 if ( !current_user_can('edit_post', $post_ID) ) 
    1910                         return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.')); 
    1911  
    1912                 extract($actual_post, EXTR_SKIP); 
    1913  
    1914                 if ( ('publish' == $post_status) && !current_user_can('publish_posts') ) 
    1915                         return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.')); 
    1916  
    1917                 $post_title = xmlrpc_getposttitle($content); 
    1918                 $post_category = xmlrpc_getpostcategory($content); 
    1919                 $post_content = xmlrpc_removepostdata($content); 
    1920  
    1921                 $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt'); 
    1922  
    1923                 $result = wp_update_post($postdata); 
    1924  
    1925                 if ( !$result ) 
    1926                         return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.')); 
    1927  
    1928                 $this->attach_uploads( $ID, $post_content ); 
    1929  
    1930                 return true; 
    1931         } 
    1932  
    1933         /** 
    1934          * Remove a post. 
    1935          * 
    1936          * @since 1.5.0 
    1937          * 
    1938          * @param array $args Method parameters. 
    1939          * @return bool True when post is deleted. 
    1940          */ 
    1941         function blogger_deletePost($args) { 
    1942                 $this->escape($args); 
    1943  
    1944                 $post_ID     = (int) $args[1]; 
    1945                 $username  = $args[2]; 
    1946                 $password   = $args[3]; 
    1947                 $publish     = $args[4]; 
    1948  
    1949                 if ( !$user = $this->login($username, $password) ) 
    1950                         return $this->error; 
    1951  
    1952                 do_action('xmlrpc_call', 'blogger.deletePost'); 
    1953  
    1954                 $actual_post = wp_get_single_post($post_ID,ARRAY_A); 
    1955  
    1956                 if ( !$actual_post || $actual_post['post_type'] != 'post' ) 
    1957                         return new IXR_Error(404, __('Sorry, no such post.')); 
    1958  
    1959                 if ( !current_user_can('edit_post', $post_ID) ) 
    1960                         return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.')); 
    1961  
    1962                 $result = wp_delete_post($post_ID); 
    1963  
    1964                 if ( !$result ) 
    1965                         return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.')); 
    1966  
    1967                 return true; 
    1968         } 
    1969  
    1970         /* MetaWeblog API functions 
    1971          * specs on wherever Dave Winer wants them to be 
    1972          */ 
    1973  
    1974         /** 
    1975          * Create a new post. 
    1976          * 
    1977          * @since 1.5.0 
    1978          * 
    1979          * @param array $args Method parameters. 
    1980          * @return int 
    1981          */ 
    1982         function mw_newPost($args) { 
    1983                 $this->escape($args); 
    1984  
    1985                 $blog_ID     = (int) $args[0]; // we will support this in the near future 
    1986                 $username  = $args[1]; 
    1987                 $password   = $args[2]; 
    1988                 $content_struct = $args[3]; 
    1989                 $publish     = $args[4]; 
    1990  
    1991                 if ( !$user = $this->login($username, $password) ) 
    1992                         return $this->error; 
    1993  
    1994                 do_action('xmlrpc_call', 'metaWeblog.newPost'); 
    1995  
    1996                 $cap = ( $publish ) ? 'publish_posts' : 'edit_posts'; 
    1997                 $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' ); 
    1998                 $post_type = 'post'; 
    1999                 $page_template = ''; 
    2000                 if ( !empty( $content_struct['post_type'] ) ) { 
    2001                         if ( $content_struct['post_type'] == 'page' ) { 
    2002                                 $cap = ( $publish ) ? 'publish_pages' : 'edit_pages'; 
    2003                                 $error_message = __( 'Sorry, you are not allowed to publish pages on this site.' ); 
    2004                                 $post_type = 'page'; 
    2005                                 if ( !empty( $content_struct['wp_page_template'] ) ) 
    2006                                         $page_template = $content_struct['wp_page_template']; 
    2007                         } elseif ( $content_struct['post_type'] == 'post' ) { 
    2008                                 // This is the default, no changes needed 
    2009                         } else { 
    2010                                 // No other post_type values are allowed here 
    2011                                 return new IXR_Error( 401, __( 'Invalid post type.' ) ); 
    2012                         } 
    2013                 } 
    2014  
    2015                 if ( !current_user_can( $cap ) ) 
    2016                         return new IXR_Error( 401, $error_message ); 
    2017  
    2018                 // Let WordPress generate the post_name (slug) unless 
    2019                 // one has been provided. 
    2020                 $post_name = ""; 
    2021                 if ( isset($content_struct["wp_slug"]) ) 
    2022                         $post_name = $content_struct["wp_slug"]; 
    2023  
    2024                 // Only use a password if one was given. 
    2025                 if ( isset($content_struct["wp_password"]) ) 
    2026                         $post_password = $content_struct["wp_password"]; 
    2027  
    2028                 // Only set a post parent if one was provided. 
    2029                 if ( isset($content_struct["wp_page_parent_id"]) ) 
    2030                         $post_parent = $content_struct["wp_page_parent_id"]; 
    2031  
    2032                 // Only set the menu_order if it was provided. 
    2033                 if ( isset($content_struct["wp_page_order"]) ) 
    2034                         $menu_order = $content_struct["wp_page_order"]; 
    2035  
    2036                 $post_author = $user->ID; 
    2037  
    2038                 // If an author id was provided then use it instead. 
    2039                 if ( isset($content_struct["wp_author_id"]) && ($user->ID != $content_struct["wp_author_id"]) ) { 
    2040                         switch ( $post_type ) { 
    2041                                 case "post": 
    2042                                         if ( !current_user_can("edit_others_posts") ) 
    2043                                                 return(new IXR_Error(401, __("You are not allowed to post as this user"))); 
    2044                                         break; 
    2045                                 case "page": 
    2046                                         if ( !current_user_can("edit_others_pages") ) 
    2047                                                 return(new IXR_Error(401, __("You are not allowed to create pages as this user"))); 
    2048                                         break; 
    2049                                 default: 
    2050                                         return(new IXR_Error(401, __("Invalid post type."))); 
    2051                                         break; 
    2052                         } 
    2053                         $post_author = $content_struct["wp_author_id"]; 
    2054                 } 
    2055  
    2056                 $post_title = $content_struct['title']; 
    2057                 $post_content = $content_struct['description']; 
    2058  
    2059                 $post_status = $publish ? 'publish' : 'draft'; 
    2060  
    2061                 if ( isset( $content_struct["{$post_type}_status"] ) ) { 
    2062                         switch ( $content_struct["{$post_type}_status"] ) { 
    2063                                 case 'draft': 
    2064                                 case 'private': 
    2065                                 case 'publish': 
    2066                                         $post_status = $content_struct["{$post_type}_status"]; 
    2067                                         break; 
    2068                                 case 'pending': 
    2069                                         // Pending is only valid for posts, not pages. 
    2070                                         if ( $post_type === 'post' ) 
    2071                                                 $post_status = $content_struct["{$post_type}_status"]; 
    2072                                         break; 
    2073                                 default: 
    2074                                         $post_status = $publish ? 'publish' : 'draft'; 
    2075                                         break; 
    2076                         } 
    2077                 } 
    2078  
    2079                 $post_excerpt = $content_struct['mt_excerpt']; 
    2080                 $post_more = $content_struct['mt_text_more']; 
    2081  
    2082                 $tags_input = $content_struct['mt_keywords']; 
    2083  
    2084                 if ( isset($content_struct["mt_allow_comments"]) ) { 
    2085                         if ( !is_numeric($content_struct["mt_allow_comments"]) ) { 
    2086                                 switch ( $content_struct["mt_allow_comments"] ) { 
    2087                                         case "closed": 
    2088                                                 $comment_status = "closed"; 
    2089                                                 break; 
    2090                                         case "open": 
    2091                                                 $comment_status = "open"; 
    2092                                                 break; 
    2093                                         default: 
    2094                                                 $comment_status = get_option("default_comment_status"); 
    2095                                                 break; 
    2096                                 } 
    2097                         } else { 
    2098                                 switch ( (int) $content_struct["mt_allow_comments"] ) { 
    2099                                         case 0: 
    2100                                         case 2: 
    2101                                                 $comment_status = "closed"; 
    2102                                                 break; 
    2103                                         case 1: 
    2104                                                 $comment_status = "open"; 
    2105                                                 break; 
    2106                                         default: 
    2107                                                 $comment_status = get_option("default_comment_status"); 
    2108                                                 break; 
    2109                                 } 
    2110                         } 
    2111                 } else { 
    2112                         $comment_status = get_option("default_comment_status"); 
    2113                 } 
    2114  
    2115                 if ( isset($content_struct["mt_allow_pings"]) ) { 
    2116                         if ( !is_numeric($content_struct["mt_allow_pings"]) ) { 
    2117                                 switch ( $content_struct['mt_allow_pings'] ) { 
    2118                                         case "closed": 
    2119                                                 $ping_status = "closed"; 
    2120                                                 break; 
    2121                                         case "open": 
    2122                                                 $ping_status = "open"; 
    2123                                                 break; 
    2124                                         default: 
    2125                                                 $ping_status = get_option("default_ping_status"); 
    2126                                                 break; 
    2127                                 } 
    2128                         } else { 
    2129                                 switch ( (int) $content_struct["mt_