[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-forums/bbpress/ -> xmlrpc.php (source)

   1  <?php
   2  /**
   3   * XML-RPC protocol support for bbPress
   4   *
   5   * @since 1.0
   6   * @package bbPress
   7   */
   8  
   9  
  10  
  11  /**
  12   * Whether this is an XML-RPC Request
  13   *
  14   * @since 1.0
  15   * @var bool
  16   */
  17  define( 'XMLRPC_REQUEST', true );
  18  
  19  // Get rid of cookies sent by some browser-embedded clients
  20  $_COOKIE = array();
  21  
  22  // A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default
  23  if ( !isset( $HTTP_RAW_POST_DATA ) ) {
  24      $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
  25  }
  26  
  27  // Fix for mozBlog and other cases where '<?xml' isn't on the very first line
  28  if ( isset( $HTTP_RAW_POST_DATA ) ) {
  29      $HTTP_RAW_POST_DATA = trim( $HTTP_RAW_POST_DATA );
  30  }
  31  
  32  // Load bbPress
  33  require_once ( './bb-load.php' );
  34  
  35  
  36  
  37  // If the service discovery data is requested then return it and exit
  38  if ( isset( $_GET['rsd'] ) ) {
  39      header( 'Content-Type: text/xml; charset=UTF-8', true );
  40      echo '<?xml version="1.0" encoding="UTF-8"?'.'>' . "\n";
  41      echo '<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">' . "\n";
  42      echo '    <service>' . "\n";
  43      echo '        <engineName>bbPress</engineName>' . "\n";
  44      echo '        <engineLink>http://bbpress.org/</engineLink>' . "\n";
  45      echo '        <homePageLink>' . bb_get_uri() . '</homePageLink>' . "\n";
  46      echo '        <apis>' . "\n";
  47      echo '            <api name="bbPress" blogID="1" preferred="true" apiLink="' . bb_get_uri( 'xmlrpc.php' ) . '" />' . "\n";
  48      echo '        </apis>' . "\n";
  49      echo '    </service>' . "\n";
  50      echo '</rsd>' . "\n";
  51      exit;
  52  }
  53  
  54  // Load the XML-RPC server/client classes
  55  if ( ! class_exists( 'IXR_Value' ) ) {
  56      require_once( BACKPRESS_PATH . '/class.ixr.php' );
  57  }
  58  
  59  /**
  60   * XML-RPC server class to allow for remote publishing
  61   *
  62   * @since 1.0
  63   * @package bbPress
  64   * @subpackage Publishing
  65   * @uses class IXR_Server
  66   */
  67  class BB_XMLRPC_Server extends IXR_Server
  68  {
  69      /**
  70       * Stores the last error generated by the class
  71       *
  72       * @since 1.0
  73       * @var object|boolean An instance of the IXR_Error class or false if no error exists
  74       */
  75      var $error = false;
  76  
  77      /**
  78       * Site options which can be manipulated using XML-RPC
  79       *
  80       * @since 1.0
  81       * @var array
  82       */
  83      var $site_options = array();
  84  
  85      /**
  86       * Whether read-only methods require authentication
  87       *
  88       * @since 1.0
  89       * @var boolean
  90       **/
  91      var $auth_readonly = false;
  92  
  93      /**
  94       * Whether user switching is allowed
  95       *
  96       * @since 1.0
  97       * @var boolean
  98       **/
  99      var $allow_user_switching = false;
 100  
 101      /**
 102       * Initialises the XML-RPC server
 103       *
 104       * @since 1.0
 105       * @return void
 106       */
 107  	function __construct()
 108      {
 109          // bbPress publishing API
 110          if ( bb_get_option( 'enable_xmlrpc' ) ) {
 111              $this->methods = array(
 112                  // - Demo
 113                  'demo.sayHello'         => 'this:sayHello',
 114                  'demo.addTwoNumbers'    => 'this:addTwoNumbers',
 115                  // - Forums
 116                  'bb.getForumCount'      => 'this:bb_getForumCount',
 117                  'bb.getForums'          => 'this:bb_getForums',
 118                  'bb.getForum'           => 'this:bb_getForum',
 119                  'bb.newForum'           => 'this:bb_newForum',
 120                  'bb.editForum'          => 'this:bb_editForum',
 121                  'bb.deleteForum'        => 'this:bb_deleteForum',
 122                  // - Topics
 123                  'bb.getTopicCount'      => 'this:bb_getTopicCount',
 124                  'bb.getTopics'          => 'this:bb_getTopics',
 125                  'bb.getTopic'           => 'this:bb_getTopic',
 126                  'bb.newTopic'           => 'this:bb_newTopic',
 127                  'bb.editTopic'          => 'this:bb_editTopic',
 128                  'bb.deleteTopic'        => 'this:bb_deleteTopic',        // Also undeletes
 129                  'bb.moveTopic'          => 'this:bb_moveTopic',
 130                  'bb.stickTopic'         => 'this:bb_stickTopic',         // Also unsticks
 131                  'bb.closeTopic'         => 'this:bb_closeTopic',         // Also opens
 132                  'bb.getTopicStatusList' => 'this:bb_getTopicStatusList',
 133                  // - Posts (replies)
 134                  'bb.getPostCount'      => 'this:bb_getPostCount',
 135                  'bb.getPosts'          => 'this:bb_getPosts',
 136                  'bb.getPost'           => 'this:bb_getPost',
 137                  'bb.newPost'           => 'this:bb_newPost',
 138                  'bb.editPost'          => 'this:bb_editPost',
 139                  'bb.deletePost'        => 'this:bb_deletePost',          // Also undeletes
 140                  'bb.getPostStatusList' => 'this:bb_getPostStatusList',
 141                  // - Topic Tags
 142                  'bb.getHotTopicTags'   => 'this:bb_getHotTopicTags',
 143                  'bb.getTopicTagCount'  => 'this:bb_getTopicTagCount',
 144                  'bb.getTopicTags'      => 'this:bb_getTopicTags',
 145                  'bb.getTopicTag'       => 'this:bb_getTopicTag',
 146                  'bb.addTopicTags'      => 'this:bb_addTopicTags',
 147                  'bb.removeTopicTags'   => 'this:bb_removeTopicTags',
 148                  'bb.renameTopicTag'    => 'this:bb_renameTopicTag',
 149                  'bb.mergeTopicTags'    => 'this:bb_mergeTopicTags',
 150                  'bb.destroyTopicTag'   => 'this:bb_destroyTopicTag',
 151                  // - Options
 152                  'bb.getOptions'        => 'this:bb_getOptions',
 153                  'bb.setOptions'        => 'this:bb_setOptions'
 154              );
 155          }
 156  
 157          // Pingback
 158          if ( bb_get_option( 'enable_pingback' ) ) {
 159              $this->methods = array_merge( (array)$this->methods, array(
 160                  'pingback.ping' => 'this:pingback_ping',
 161                  'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks'
 162              ) );
 163          }
 164  
 165          // Tells read-only methods whether they require authentication or not
 166          $this->auth_readonly = apply_filters( 'bb_xmlrpc_auth_readonly', $this->auth_readonly );
 167  
 168          // Whether or not to allow user switching
 169          $this->allow_user_switching = bb_get_option( 'bb_xmlrpc_allow_user_switching' );
 170  
 171          $this->initialise_site_option_info();
 172          $this->methods = apply_filters( 'bb_xmlrpc_methods', $this->methods );
 173          $this->IXR_Server( $this->methods );
 174      }
 175  
 176  	function BB_XMLRPC_Server()
 177      {
 178          $this->__construct();
 179      }
 180  
 181      /**
 182       * Utility methods
 183       */
 184  
 185      /**
 186       * Checks the user credentials supplied in the request to make sure they are valid
 187       *
 188       * @since 1.0
 189       * @return integer|boolean The user id if the user is valid, otherwise false
 190       * @param string $user_login The users login
 191       * @param string $user_pass The users password in plain text
 192       * @param string $capability The capability to check (optional)
 193       * @param string $message The message to pass back in the error if the capability check fails (optional)
 194       */
 195  	function authenticate( $user_login, $user_pass, $capability = 'read', $message = false )
 196      {
 197          if ( is_array( $user_login ) ) {
 198              $auth_user_login = (string) $user_login[0];
 199              $switch_user_login = (string) $user_login[1];
 200          } else {
 201              $auth_user_login = (string) $user_login;
 202              $switch_user_login = false;
 203          }
 204          
 205          // Check the login
 206          $user = bb_check_login( $auth_user_login, $user_pass );
 207          if ( !$user || is_wp_error( $user ) ) {
 208              $this->error = new IXR_Error( 403, __( 'Authentication failed.' ) );
 209              return false;
 210          }
 211  
 212          // Set the current user
 213          $user = bb_set_current_user( $user->ID );
 214  
 215          // Make sure they are allowed to do this
 216          if ( !bb_current_user_can( $capability ) ) {
 217              if ( !$message ) {
 218                  $message = __( 'You do not have permission to read this.' );
 219              }
 220              $this->error = new IXR_Error( 403, $message );
 221              return false;
 222          }
 223  
 224          // Switch the user if requested and allowed
 225          if ( $switch_user_login && $this->allow_user_switching && bb_current_user_can( 'edit_users' ) ) {
 226              $user = $this->switch_user( $switch_user_login, $capability, $message );
 227          }
 228  
 229          return $user;
 230      }
 231  
 232      /**
 233       * Switches the currently active user for incognito actions
 234       *
 235       * @since 1.0
 236       * @return integer|boolean The user id if the user is valid, otherwise false
 237       * @param string $user_login The users login
 238       * @param string $capability The capability to check (optional)
 239       * @param string $message The message to pass back in the error if the capability check fails (optional)
 240       */
 241  	function switch_user( $user_login, $capability = 'read', $message = false )
 242      {
 243          // Just get the user, authentication has already been established by the 
 244          $user = bb_get_user( $user_login, array( 'by' => 'login' ) );
 245          if ( !$user || is_wp_error( $user ) ) {
 246              $this->error = new IXR_Error( 400, __( 'User switching failed, the requested user does not exist.' ) );
 247              return false;
 248          }
 249  
 250          // Set the current user
 251          $user = bb_set_current_user( $user->ID );
 252  
 253          // Make sure they are allowed to do this
 254          if ( !bb_current_user_can( $capability ) ) {
 255              if ( !$message ) {
 256                  $message = __( 'You do not have permission to read this.' );
 257              }
 258              $this->error = new IXR_Error( 403, $message );
 259              return false;
 260          }
 261  
 262          return $user;
 263      }
 264  
 265      /**
 266       * Sanitises data from XML-RPC request parameters
 267       *
 268       * @since 1.0
 269       * @return mixed The sanitised variable, should come back with the same type
 270       * @param $array mixed The variable to be sanitised
 271       * @uses $bbdb BackPress database class instance
 272       */
 273  	function escape( &$array )
 274      {
 275          global $bbdb;
 276  
 277          if ( !is_array( $array ) ) {
 278              // Escape it
 279              $array = $bbdb->escape( $array );
 280          } elseif ( count( $array ) ) {
 281              foreach ( (array) $array as $k => $v ) {
 282                  if ( is_array( $v ) ) {
 283                      // Recursively sanitize arrays
 284                      $this->escape( $array[$k] );
 285                  } elseif ( is_object( $v ) ) {
 286                      // Don't sanitise objects - shouldn't happen anyway
 287                  } else {
 288                      // Escape it
 289                      $array[$k] = $bbdb->escape( $v );
 290                  }
 291              }
 292          }
 293  
 294          return $array;
 295      }
 296  
 297      /**
 298       * Prepares forum data for return in an XML-RPC object
 299       *
 300       * @since 1.0
 301       * @return array The prepared forum data
 302       * @param array|object The unprepared forum data
 303       **/
 304  	function prepare_forum( $forum )
 305      {
 306          // Cast to an array
 307          $_forum = (array) $forum;
 308          // Set the URI
 309          $_forum['forum_uri'] = get_forum_link( $_forum['forum_id'] );
 310          // Give this a definite value
 311          if ( !isset( $_forum['forum_is_category'] ) ) {
 312              $_forum['forum_is_category'] = 0;
 313          }
 314          // Allow plugins to modify the data
 315          return apply_filters( 'bb_xmlrpc_prepare_forum', $_forum, (array) $forum );
 316      }
 317  
 318      /**
 319       * Prepares topic data for return in an XML-RPC object
 320       *
 321       * @since 1.0
 322       * @return array The prepared topic data
 323       * @param array|object The unprepared topic data
 324       **/
 325  	function prepare_topic( $topic )
 326      {
 327          // Cast to an array
 328          $_topic = (array) $topic;
 329          // Set the URI
 330          $_topic['topic_uri'] = get_topic_link( $_topic['topic_id'] );
 331          // Set readable times
 332          $_topic['topic_start_time_since'] = bb_since( $_topic['topic_start_time'] );
 333          $_topic['topic_time_since'] = bb_since( $_topic['topic_time'] );
 334          // Set the display names
 335          $_topic['topic_poster_display_name'] = get_user_display_name( $_topic['topic_poster'] );
 336          $_topic['topic_last_poster_display_name'] = get_user_display_name( $_topic['topic_last_poster'] );
 337          // Remove some sensitive user ids
 338          unset(
 339              $_topic['topic_poster'],
 340              $_topic['topic_last_poster']
 341          );
 342          // Allow plugins to modify the data
 343          return apply_filters( 'bb_xmlrpc_prepare_topic', $_topic, (array) $topic );
 344      }
 345  
 346      /**
 347       * Prepares post data for return in an XML-RPC object
 348       *
 349       * @since 1.0
 350       * @return array The prepared post data
 351       * @param array|object The unprepared post data
 352       **/
 353  	function prepare_post( $post )
 354      {
 355          // Cast to an array
 356          $_post = (array) $post;
 357          // Set the URI
 358          $_post['post_uri'] = get_post_link( $_post['post_id'] );
 359          // Set readable times
 360          $_post['post_time_since'] = bb_since( $_post['post_time'] );
 361          // Set the display names
 362          $_post['poster_display_name'] = get_user_display_name( $_post['poster_id'] );
 363          // Remove some sensitive data
 364          unset(
 365              $_post['poster_id'],
 366              $_post['poster_ip'],
 367              $_post['pingback_queued']
 368          );
 369          // Allow plugins to modify the data
 370          return apply_filters( 'bb_xmlrpc_prepare_post', $_post, (array) $post );
 371      }
 372  
 373      /**
 374       * Prepares topic tag data for return in an XML-RPC object
 375       *
 376       * @since 1.0
 377       * @return array The prepared topic tag data
 378       * @param array|object The unprepared topic tag data
 379       **/
 380  	function prepare_topic_tag( $tag )
 381      {
 382          // Cast to an array
 383          $_tag = (array) $tag;
 384          // Set the URI
 385          $_tag['topic_tag_uri'] = bb_get_tag_link( $tag );
 386          // Consistent nomenclature
 387          $_tag['topic_tag_name'] = (string) $_tag['name'];
 388          $_tag['topic_tag_slug'] = (string) $_tag['slug'];
 389          $_tag['topic_tag_count'] = (int) $_tag['count'];
 390          // Remove some sensitive data
 391          unset(
 392              $_tag['object_id'],
 393              $_tag['name'],
 394              $_tag['slug'],
 395              $_tag['count'],
 396              $_tag['term_id'],
 397              $_tag['term_group'],
 398              $_tag['term_taxonomy_id'],
 399              $_tag['taxonomy'],
 400              $_tag['description'],
 401              $_tag['parent'],
 402              $_tag['count'],
 403              $_tag['user_id'],
 404              $_tag['tag_id'],
 405              $_tag['tag'],
 406              $_tag['raw_tag'],
 407              $_tag['tag_count']
 408          );
 409          // Allow plugins to modify the data
 410          return apply_filters( 'bb_xmlrpc_prepare_topic_tag', $_tag, (array) $tag );
 411      }
 412  
 413  
 414  
 415      /**
 416       * bbPress publishing API - Demo XML-RPC methods
 417       */
 418  
 419      /**
 420       * Hello world demo function for XML-RPC
 421       *
 422       * @since 1.0
 423       * @return string The phrase 'Hello!'
 424       * @param array $args Arguments passed by the XML-RPC call
 425       * @param string $args[0] The username for authentication
 426       * @param string $args[1] The password for authentication
 427       *
 428       * XML-RPC request to get a greeting
 429       * <methodCall>
 430       *     <methodName>demo.sayHello</methodName>
 431       *     <params>
 432       *         <param><value><string>joeblow</string></value></param>
 433       *         <param><value><string>123password</string></value></param>
 434       *     </params>
 435       * </methodCall>
 436       */
 437  	function sayHello( $args )
 438      {
 439          // Escape args
 440          $this->escape( $args );
 441  
 442          // Get the login credentials
 443          $username = $args[0];
 444          $password = (string) $args[1];
 445  
 446          // Check the user is valid
 447          if ( $this->auth_readonly && !$this->authenticate( $username, $password ) ) {
 448              return $this->error;
 449          }
 450  
 451          return 'Hello!';
 452      }
 453  
 454      /**
 455       * Adds two numbers together as a demo of XML-RPC
 456       *
 457       * @since 1.0
 458       * @return integer The sum of the two supplied numbers
 459       * @param array $args Arguments passed by the XML-RPC call
 460       * @param string $args[0] The username for authentication
 461       * @param string $args[1] The password for authentication
 462       * @param integer $args[2] The first number to be added
 463       * @param integer $args[3] The second number to be added
 464       *
 465       * XML-RPC request to get the sum of two numbers
 466       * <methodCall>
 467       *     <methodName>demo.addTwoNumbers</methodName>
 468       *     <params>
 469       *         <param><value><string>joeblow</string></value></param>
 470       *         <param><value><string>123password</string></value></param>
 471       *         <param><value><int>5</int></value></param>
 472       *         <param><value><int>102</int></value></param>
 473       *     </params>
 474       * </methodCall>
 475       */
 476  	function addTwoNumbers( $args )
 477      {
 478          // Escape args
 479          $this->escape( $args );
 480  
 481          // Get the login credentials
 482          $username = $args[0];
 483          $password = (string) $args[1];
 484  
 485          // Check the user is valid
 486          if ( $this->auth_readonly && !$this->authenticate( $username, $password ) ) {
 487              return $this->error;
 488          }
 489  
 490          $number1 = (int) $args[2];
 491          $number2 = (int) $args[3];
 492  
 493          return ( $number1 + $number2 );
 494      }
 495  
 496  
 497  
 498      /**
 499       * bbPress publishing API - Forum XML-RPC methods
 500       */
 501  
 502      /**
 503       * Returns a numerical count of forums
 504       *
 505       * @since 1.0
 506       * @return integer|object The number of forums when successfully executed or an IXR_Error object on failure
 507       * @param array $args Arguments passed by the XML-RPC call
 508       * @param string $args[0] The username for authentication
 509       * @param string $args[1] The password for authentication
 510       * @param integer|string $args[2] The parent forum's id or slug (optional)
 511       * @param integer $args[3] The depth of child forums to retrieve (optional)
 512       *
 513       * XML-RPC request to get a count of all forums in the bbPress instance
 514       * <methodCall>
 515       *     <methodName>bb.getForumCount</methodName>
 516       *     <params>
 517       *         <param><value><string>joeblow</string></value></param>
 518       *         <param><value><string>123password</string></value></param>
 519       *     </params>
 520       * </methodCall>
 521       *
 522       * XML-RPC request to get a count of all child forums in the forum with id number 34
 523       * <methodCall>
 524       *     <methodName>bb.getForumCount</methodName>
 525       *     <params>
 526       *         <param><value><string>joeblow</string></value></param>
 527       *         <param><value><string>123password</string></value></param>
 528       *         <param><value><int>34</int></value></param>
 529       *     </params>
 530       * </methodCall>
 531       *
 532       * XML-RPC request to get a count of all child forums in the forum with slug "first-forum"
 533       * <methodCall>
 534       *     <methodName>bb.getForumCount</methodName>
 535       *     <params>
 536       *         <param><value><string>joeblow</string></value></param>
 537       *         <param><value><string>123password</string></value></param>
 538       *         <param><value><string>first-forum</string></value></param>
 539       *     </params>
 540       * </methodCall>
 541       *
 542       * XML-RPC request to get a count of all child forums in the forum with id number 34 no more than 2 forums deep in the hierarchy
 543       * <methodCall>
 544       *     <methodName>bb.getForumCount</methodName>
 545       *     <params>
 546       *         <param><value><string>joeblow</string></value></param>
 547       *         <param><value><string>123password</string></value></param>
 548       *         <param><value><int>34</int></value></param>
 549       *         <param><value><int>2</int></value></param>
 550       *     </params>
 551       * </methodCall>
 552       */
 553  	function bb_getForumCount( $args )
 554      {
 555          do_action( 'bb_xmlrpc_call', 'bb.getForumCount' );
 556  
 557          // Escape args
 558          $this->escape( $args );
 559  
 560          // Get the login credentials
 561          $username = $args[0];
 562          $password = (string) $args[1];
 563  
 564          // Check the user is valid
 565          if ( $this->auth_readonly ) {
 566              $user = $this->authenticate( $username, $password );
 567          }
 568  
 569          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getForumCount' );
 570  
 571          // If an error was raised by authentication or by an action then return it
 572          if ( $this->error ) {
 573              return $this->error;
 574          }
 575  
 576          // Setup an array to store arguments to pass to bb_get_forums() function
 577          $get_forums_args = array(
 578              'child_of' => 0,
 579              'hierarchical' => 0,
 580              'depth' => 0
 581          );
 582  
 583          // Can be numeric id or slug
 584          $forum_id = isset( $args[2] ) ? $args[2] : false;
 585  
 586          if ( $forum_id ) {
 587              // Check for bad data
 588              if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) {
 589                  $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) );
 590                  return $this->error;
 591              }
 592              // Check the requested forum exists
 593              if ( !$forum = bb_get_forum( $forum_id ) ) {
 594                  $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) );
 595                  return $this->error;
 596              }
 597              // Add the specific forum to the arguments
 598              $get_forums_args['child_of'] = (int) $forum->forum_id;
 599          }
 600  
 601          // Can only be an integer
 602          $depth = (int) $args[3];
 603  
 604          if ( $depth > 0 ) {
 605              // Add the depth to traverse to the arguments
 606              $get_forums_args['depth'] = $depth;
 607              // Only make it hierarchical if the depth > 1
 608              if ( $depth > 1 ) {
 609                  $get_forums_args['hierarchical'] = 1;
 610              }
 611          }
 612  
 613          // Get the forums. Return 0 when no forums exist
 614          if ( !$forums = bb_get_forums( $get_forums_args ) ) {
 615              $count = 0;
 616          } else {
 617              $count = count( $forums );
 618          }
 619  
 620          do_action( 'bb_xmlrpc_call_return', 'bb.getForumCount' );
 621  
 622          // Return a count of the forums
 623          return $count;
 624      }
 625  
 626      /**
 627       * Returns details of multiple forums
 628       *
 629       * @since 1.0
 630       * @return array|object An array containing details of all returned forums when successfully executed or an IXR_Error object on failure
 631       * @param array $args Arguments passed by the XML-RPC call
 632       * @param string $args[0] The username for authentication
 633       * @param string $args[1] The password for authentication
 634       * @param integer|string $args[2] The parent forum's id or slug (optional)
 635       * @param integer $args[3] The depth of child forums to retrieve (optional)
 636       *
 637       * XML-RPC request to get all forums in the bbPress instance
 638       * <methodCall>
 639       *     <methodName>bb.getForums</methodName>
 640       *     <params>
 641       *         <param><value><string>joeblow</string></value></param>
 642       *         <param><value><string>123password</string></value></param>
 643       *     </params>
 644       * </methodCall>
 645       *
 646       * XML-RPC request to get all child forums in the forum with id number 34
 647       * <methodCall>
 648       *     <methodName>bb.getForums</methodName>
 649       *     <params>
 650       *         <param><value><string>joeblow</string></value></param>
 651       *         <param><value><string>123password</string></value></param>
 652       *         <param><value><int>34</int></value></param>
 653       *     </params>
 654       * </methodCall>
 655       *
 656       * XML-RPC request to get all child forums in the forum with slug "first-forum"
 657       * <methodCall>
 658       *     <methodName>bb.getForums</methodName>
 659       *     <params>
 660       *         <param><value><string>joeblow</string></value></param>
 661       *         <param><value><string>123password</string></value></param>
 662       *         <param><value><string>first-forum</string></value></param>
 663       *     </params>
 664       * </methodCall>
 665       *
 666       * XML-RPC request to get all child forums in the forum with id number 34 no more than 2 forums deep in the hierarchy
 667       * <methodCall>
 668       *     <methodName>bb.getForums</methodName>
 669       *     <params>
 670       *         <param><value><string>joeblow</string></value></param>
 671       *         <param><value><string>123password</string></value></param>
 672       *         <param><value><int>34</int></value></param>
 673       *         <param><value><int>2</int></value></param>
 674       *     </params>
 675       * </methodCall>
 676       */
 677  	function bb_getForums( $args )
 678      {
 679          do_action( 'bb_xmlrpc_call', 'bb.getForums' );
 680  
 681          // Escape args
 682          $this->escape( $args );
 683  
 684          // Get the login credentials
 685          $username = $args[0];
 686          $password = (string) $args[1];
 687  
 688          // Check the user is valid
 689          if ( $this->auth_readonly ) {
 690              $user = $this->authenticate( $username, $password );
 691          }
 692  
 693          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getForums' );
 694  
 695          // If an error was raised by authentication or by an action then return it
 696          if ( $this->error ) {
 697              return $this->error;
 698          }
 699  
 700          // Setup an array to store arguments to pass to bb_get_forums() function
 701          $get_forums_args = array(
 702              'child_of' => 0,
 703              'hierarchical' => 0,
 704              'depth' => 0
 705          );
 706  
 707          // Can be numeric id or slug
 708          $forum_id = isset( $args[2] ) ? $args[2] : false;
 709  
 710          if ( $forum_id ) {
 711              // Check for bad data
 712              if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) {
 713                  $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) );
 714                  return $this->error;
 715              }
 716              // First check the requested forum exists
 717              if ( !$forum = bb_get_forum( $forum_id ) ) {
 718                  $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) );
 719                  return $this->error;
 720              }
 721              // Add the specific forum to the arguments
 722              $get_forums_args['child_of'] = (int) $forum->forum_id;
 723          }
 724  
 725          // Can only be an integer
 726          $depth = (int) $args[3];
 727  
 728          if ( $depth > 0 ) {
 729              // Add the depth to traverse to to the arguments
 730              $get_forums_args['depth'] = $depth;
 731              // Only make it hierarchical if the depth > 1
 732              if ( $depth > 1 ) {
 733                  $get_forums_args['hierarchical'] = 1;
 734              }
 735          }
 736  
 737          // Get the forums. Return an error when no forums exist
 738          if ( !$forums = bb_get_forums( $get_forums_args ) ) {
 739              $this->error = new IXR_Error( 404, __( 'No forums found.' ) );
 740              return $this->error;
 741          }
 742  
 743          // Only include "safe" data in the array
 744          $_forums = array();
 745          foreach ( $forums as $forum ) {
 746              $_forums[] = $this->prepare_forum( $forum );
 747          }
 748  
 749          do_action( 'bb_xmlrpc_call_return', 'bb.getForums' );
 750  
 751          // Return the forums
 752          return $_forums;
 753      }
 754  
 755      /**
 756       * Returns details of a forum
 757       *
 758       * @since 1.0
 759       * @return array|object An array containing details of the returned forum when successfully executed or an IXR_Error object on failure
 760       * @param string $args[0] The username for authentication
 761       * @param string $args[1] The password for authentication
 762       * @param integer|string $args[2] The forum's id or slug
 763       *
 764       * XML-RPC request to get the forum with id number 34
 765       * <methodCall>
 766       *     <methodName>bb.getForum</methodName>
 767       *     <params>
 768       *         <param><value><string>joeblow</string></value></param>
 769       *         <param><value><string>123password</string></value></param>
 770       *         <param><value><int>34</int></value></param>
 771       *     </params>
 772       * </methodCall>
 773       *
 774       * XML-RPC request to get the forum with slug "first-forum"
 775       * <methodCall>
 776       *     <methodName>bb.getForum</methodName>
 777       *     <params>
 778       *         <param><value><string>joeblow</string></value></param>
 779       *         <param><value><string>123password</string></value></param>
 780       *         <param><value><string>first-forum</string></value></param>
 781       *     </params>
 782       * </methodCall>
 783       */
 784  	function bb_getForum( $args )
 785      {
 786          do_action( 'bb_xmlrpc_call', 'bb.getForum' );
 787  
 788          // Escape args
 789          $this->escape( $args );
 790  
 791          // Get the login credentials
 792          $username = $args[0];
 793          $password = (string) $args[1];
 794  
 795          // Check the user is valid
 796          if ( $this->auth_readonly ) {
 797              $user = $this->authenticate( $username, $password );
 798          }
 799  
 800          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getForum' );
 801  
 802          // If an error was raised by authentication or by an action then return it
 803          if ( $this->error ) {
 804              return $this->error;
 805          }
 806  
 807          // Can be numeric id or slug
 808          $forum_id = isset( $args[2] ) ? $args[2] : false;
 809  
 810          // Check for bad data
 811          if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) {
 812              $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) );
 813              return $this->error;
 814          }
 815  
 816          // Check the requested forum exists
 817          if ( !$forum = bb_get_forum( $forum_id ) ) {
 818              $this->error = new IXR_Error( 404, __( 'No forum found.' ) );
 819              return $this->error;
 820          }
 821  
 822          // Only include "safe" data in the array
 823          $forum = $this->prepare_forum( $forum );
 824  
 825          do_action( 'bb_xmlrpc_call_return', 'bb.getForum' );
 826  
 827          // Return the forums
 828          return $forum;
 829      }
 830  
 831      /**
 832       * Creates a new forum
 833       *
 834       * @since 1.0
 835       * @return array|object The forum data when successfully created or an IXR_Error object on failure
 836       * @param array $args Arguments passed by the XML-RPC call
 837       * @param string $args[0] The username for authentication
 838       * @param string $args[1] The password for authentication
 839       * @param array $args[2] The values for the various settings in the new forum
 840       * @param string $args[2]['name'] The name of the forum
 841       * @param string $args[2]['description'] The description of the forum (optional)
 842       * @param integer|string $args[2]['parent_id'] The unique id of the parent forum for this forum (optional)
 843       * @param integer $args[2]['order'] The position of the forum in the forum list (optional)
 844       * @param integer $args[2]['is_category'] Whether the forum is simply a container category (optional)
 845       *
 846       * XML-RPC request to create a new sub-forum called "A new forum" inside the parent forum with id 2
 847       * <methodCall>
 848       *     <methodName>bb.newForum</methodName>
 849       *     <params>
 850       *         <param><value><string>joeblow</string></value></param>
 851       *         <param><value><string>123password</string></value></param>
 852       *         <param><value><struct>
 853       *             <member>
 854       *                 <name>name</name>
 855       *                 <value><string>A new forum</string></value>
 856       *             </member>
 857       *             <member>
 858       *                 <name>parent_id</name>
 859       *                 <value><integer>2</integer></value>
 860       *             </member>
 861       *         </struct></value></param>
 862       *     </params>
 863       * </methodCall>
 864       */
 865  	function bb_newForum( $args )
 866      {
 867          do_action( 'bb_xmlrpc_call', 'bb.newForum' );
 868  
 869          // Escape args
 870          $this->escape( $args );
 871  
 872          // Get the login credentials
 873          $username = $args[0];
 874          $password = (string) $args[1];
 875  
 876          // Check the user is valid
 877          $user = $this->authenticate( $username, $password, 'manage_forums', __( 'You do not have permission to manage forums.' ) );
 878  
 879          do_action( 'bb_xmlrpc_call_authenticated', 'bb.newForum' );
 880  
 881          // If an error was raised by authentication or by an action then return it
 882          if ( $this->error ) {
 883              return $this->error;
 884          }
 885  
 886          // Make sure there is something for us to do
 887          if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) {
 888              $this->error = new IXR_Error( 400, __( 'The forum data is invalid.' ) );
 889              return $this->error;
 890          }
 891  
 892          $structure = (array) $args[2];
 893  
 894          // Minimum requirement is a name for the new forum
 895          if ( !isset( $structure['name'] ) || !$structure['name'] ) {
 896              $this->error = new IXR_Error( 400, __( 'The forum name is invalid.' ) );
 897              return $this->error;
 898          }
 899  
 900          // Inject structure into an array suitable for bb_new_forum()
 901          $bb_new_forum_args = array(
 902              'forum_name' => (string) $structure['name'],
 903              'forum_desc' => (string) $structure['description'],
 904              'forum_parent' => (int) $structure['parent_id'],
 905              'forum_order' => (int) $structure['order'],
 906              'forum_is_category' => (int) $structure['is_category']
 907          );
 908  
 909          // Remove empty settings so that changes to the defaults in bb_new_forum() are honoured
 910          $bb_new_forum_args = array_filter( $bb_new_forum_args );
 911  
 912          // Leave the require until the very end
 913          require_once ( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' );
 914  
 915          // Create the forum
 916          if ( !$forum_id = (int) bb_new_forum( $bb_new_forum_args ) ) {
 917              $this->error = new IXR_Error( 500, __( 'The forum could not be created.' ) );
 918              return $this->error;
 919          }
 920  
 921          // Only include "safe" data in the array
 922          $forum = $this->prepare_forum( bb_get_forum( $forum_id ) );
 923  
 924          do_action( 'bb_xmlrpc_call_return', 'bb.newForum' );
 925  
 926          return $forum;
 927      }
 928  
 929      /**
 930       * Edits an existing forum
 931       *
 932       * @since 1.0
 933       * @return array|object The forum data when successfully edited or an IXR_Error object on failure
 934       * @param array $args Arguments passed by the XML-RPC call
 935       * @param string $args[0] The username for authentication
 936       * @param string $args[1] The password for authentication
 937       * @param array $args[2] The values for the various settings in the new forum, at least one must be specified
 938       * @param integer|string $args[2]['forum_id'] The unique id of the forum to be edited
 939       * @param string $args[2]['name'] The name of the forum (optional)
 940       * @param string $args[2]['slug'] The slug for the forum (optional)
 941       * @param string $args[2]['description'] The description of the forum (optional)
 942       * @param integer $args[2]['parent_id'] The unique id of the parent forum for this forum (optional)
 943       * @param integer $args[2]['order'] The position of the forum in the forum list (optional)
 944       * @param integer $args[2]['is_category'] Whether the forum is simply a container category (optional)
 945       *
 946       * XML-RPC request to edit a forum with id 11, changing the description
 947       * <methodCall>
 948       *     <methodName>bb.editForum</methodName>
 949       *     <params>
 950       *         <param><value><string>joeblow</string></value></param>
 951       *         <param><value><string>123password</string></value></param>
 952       *         <param><value><struct>
 953       *             <member>
 954       *                 <name>forum_id</name>
 955       *                 <value><integer>11</integer></value>
 956       *             </member>
 957       *             <member>
 958       *                 <name>description</name>
 959       *                 <value><string>This is a great forum for all sorts of reasons.</string></value>
 960       *             </member>
 961       *         </struct></value></param>
 962       *     </params>
 963       * </methodCall>
 964       */
 965  	function bb_editForum( $args )
 966      {
 967          do_action( 'bb_xmlrpc_call', 'bb.editForum' );
 968  
 969          // Escape args
 970          $this->escape( $args );
 971  
 972          // Get the login credentials
 973          $username = $args[0];
 974          $password = (string) $args[1];
 975  
 976          // Check the user is valid
 977          $user = $this->authenticate( $username, $password, 'manage_forums', __( 'You do not have permission to manage forums.' ) );
 978  
 979          do_action( 'bb_xmlrpc_call_authenticated', 'bb.editForum' );
 980  
 981          // If an error was raised by authentication or by an action then return it
 982          if ( $this->error ) {
 983              return $this->error;
 984          }
 985  
 986          // Make sure there is something for us to do
 987          if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) {
 988              $this->error = new IXR_Error( 400, __( 'The forum data is invalid.' ) );
 989              return $this->error;
 990          }
 991  
 992          $structure = (array) $args[2];
 993  
 994          // Can be numeric id or slug
 995          $forum_id = isset( $structure['forum_id'] ) ? $structure['forum_id'] : false;
 996  
 997          // Check for bad data
 998          if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) {
 999              $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) );
1000              return $this->error;
1001          }
1002  
1003          // Check the requested forum exists
1004          if ( !$forum = bb_get_forum( $forum_id ) ) {
1005              $this->error = new IXR_Error( 400, __( 'No forum found.' ) );
1006              return $this->error;
1007          }
1008  
1009          // Cast the forum object as an array
1010          $forum = (array) $forum;
1011          // The forum id may have been a slug, so make sure it's an integer here
1012          $forum_id = (int) $forum['forum_id'];
1013  
1014          // Remove some unneeded indexes
1015          unset( $forum['topics'] );
1016          unset( $forum['posts'] );
1017  
1018          // Add one if it isn't there
1019          if ( !isset( $forum['forum_is_category'] ) ) {
1020              $forum['forum_is_category'] = 0;
1021          }
1022  
1023          // Validate the name for the forum
1024          if ( isset( $structure['name'] ) && !$structure['name'] ) {
1025              $this->error = new IXR_Error( 400, __( 'The forum name is invalid.' ) );
1026              return $this->error;
1027          }
1028  
1029          // Inject structure into an array suitable for bb_update_forum()
1030          $bb_update_forum_args = array(
1031              'forum_name' => $structure['name']
1032          );
1033  
1034          // Slug cannot be blank
1035          if ( isset( $structure['slug'] ) && $structure['slug'] !== '' ) {
1036              $bb_update_forum_args['forum_slug'] = $structure['slug'];
1037          }
1038  
1039          // Description can be nothing
1040          if ( isset( $structure['description'] ) ) {
1041              $bb_update_forum_args['forum_desc'] = $structure['description'];
1042          }
1043  
1044          // Parent forum ID must be an integer and it can be 0
1045          if ( isset( $structure['parent_id'] ) && is_integer( $structure['parent_id'] ) ) {
1046              $bb_update_forum_args['forum_parent'] = $structure['parent_id'];
1047          }
1048  
1049          // Order must be an integer and it can be 0
1050          if ( isset( $structure['order'] ) && is_integer( $structure['order'] ) ) {
1051              $bb_update_forum_args['forum_order'] = $structure['order'];
1052          }
1053  
1054          // Category flag must be an integer and it can be 0
1055          if ( isset( $structure['is_category'] ) && is_integer( $structure['is_category'] ) ) {
1056              $bb_update_forum_args['forum_is_category'] = $structure['is_category'];
1057          }
1058  
1059          // Merge the changes into the existing data for the forum
1060          $bb_update_forum_args = wp_parse_args( $bb_update_forum_args, $forum );
1061  
1062          // Leave the require until the very end
1063          require_once ( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' );
1064  
1065          // Update the forum
1066          if ( !bb_update_forum( $bb_update_forum_args ) ) {
1067              $this->error = new IXR_Error( 500, __( 'The forum could not be edited.' ) );
1068              return $this->error;
1069          }
1070  
1071          // Only include "safe" data in the array
1072          $forum = $this->prepare_forum( bb_get_forum( $forum_id ) );
1073  
1074          do_action( 'bb_xmlrpc_call_return', 'bb.editForum' );
1075  
1076          return $forum;
1077      }
1078  
1079      /**
1080       * Deletes a forum
1081       *
1082       * @since 1.0
1083       * @return integer|object 1 when successfully deleted or an IXR_Error object on failure
1084       * @param array $args Arguments passed by the XML-RPC call
1085       * @param string $args[0] The username for authentication
1086       * @param string $args[1] The password for authentication
1087       * @param integer|string $args[2] The unique id of the forum to be deleted
1088       *
1089       * XML-RPC request to delete a forum with the slug "naughty-forum"
1090       * <methodCall>
1091       *     <methodName>bb.deleteForum</methodName>
1092       *     <params>
1093       *         <param><value><string>joeblow</string></value></param>
1094       *         <param><value><string>123password</string></value></param>
1095       *         <param><value><string>naughty-forum</string></value></param>
1096       *     </params>
1097       * </methodCall>
1098       */
1099  	function bb_deleteForum( $args )
1100      {
1101          do_action( 'bb_xmlrpc_call', 'bb.deleteForum' );
1102  
1103          // Escape args
1104          $this->escape( $args );
1105  
1106          // Get the login credentials
1107          $username = $args[0];
1108          $password = (string) $args[1];
1109  
1110          // Check the user is valid
1111          $user = $this->authenticate( $username, $password, 'delete_forums', __( 'You do not have permission to delete forums.' ) );
1112  
1113          do_action( 'bb_xmlrpc_call_authenticated', 'bb.deleteForum' );
1114  
1115          // If an error was raised by authentication or by an action then return it
1116          if ( $this->error ) {
1117              return $this->error;
1118          }
1119  
1120          // Can be numeric id or slug
1121          $forum_id = isset( $args[2] ) ? $args[2] : false;
1122  
1123          // Check for bad data
1124          if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) {
1125              $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) );
1126              return $this->error;
1127          }
1128  
1129          // Check the requested forum exists
1130          if ( !$forum = bb_get_forum( $forum_id ) ) {
1131              $this->error = new IXR_Error( 400, __( 'No forum found.' ) );
1132              return $this->error;
1133          }
1134  
1135          // Cast the forum object as an array
1136          $forum = (array) $forum;
1137          // The forum id may have been a slug, so make sure it's an integer here
1138          $forum_id = (int) $forum['forum_id'];
1139  
1140          // Make sure they are allowed to delete this forum specifically
1141          if ( !bb_current_user_can( 'delete_forum', $forum_id ) ) {
1142              $this->error = new IXR_Error( 403, __( 'You do not have permission to delete this forum.' ) );
1143              return $this->error;
1144          }
1145  
1146          // Leave the require until the very end
1147          require_once ( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' );
1148  
1149          // Delete the forum
1150          if ( !bb_delete_forum( $forum_id ) ) {
1151              $this->error = new IXR_Error( 500, __( 'The forum could not be deleted.' ) );
1152              return $this->error;
1153          }
1154  
1155          $result = 1;
1156  
1157          do_action( 'bb_xmlrpc_call_return', 'bb.deleteForum' );
1158  
1159          return $result;
1160      }
1161  
1162  
1163  
1164      /**
1165       * bbPress publishing API - Topic XML-RPC methods
1166       */
1167  
1168      /**
1169       * Returns a numerical count of topics
1170       *
1171       * @since 1.0
1172       * @return integer|object The number of topics when successfully executed or an IXR_Error object on failure
1173       * @param array $args Arguments passed by the XML-RPC call
1174       * @param string $args[0] The username for authentication
1175       * @param string $args[1] The password for authentication
1176       * @param integer|string $args[2] The forum id or slug (optional)
1177       *
1178       * XML-RPC request to get a count of all topics in the bbPress instance
1179       * <methodCall>
1180       *     <methodName>bb.getTopicCount</methodName>
1181       *     <params>
1182       *         <param><value><string>joeblow</string></value></param>
1183       *         <param><value><string>123password</string></value></param>
1184       *     </params>
1185       * </methodCall>
1186       *
1187       * XML-RPC request to get a count of all topics in the forum with id number 34
1188       * <methodCall>
1189       *     <methodName>bb.getTopicCount</methodName>
1190       *     <params>
1191       *         <param><value><string>joeblow</string></value></param>
1192       *         <param><value><string>123password</string></value></param>
1193       *         <param><value><int>34</int></value></param>
1194       *     </params>
1195       * </methodCall>
1196       *
1197       * XML-RPC request to get a count of all topics in the forum with slug "first-forum"
1198       * <methodCall>
1199       *     <methodName>bb.getTopicCount</methodName>
1200       *     <params>
1201       *         <param><value><string>joeblow</string></value></param>
1202       *         <param><value><string>123password</string></value></param>
1203       *         <param><value><string>first-forum</string></value></param>
1204       *     </params>
1205       * </methodCall>
1206       */
1207  	function bb_getTopicCount( $args )
1208      {
1209          do_action( 'bb_xmlrpc_call', 'bb.getTopicCount' );
1210  
1211          // Escape args
1212          $this->escape( $args );
1213  
1214          // Get the login credentials
1215          $username = $args[0];
1216          $password = (string) $args[1];
1217  
1218          // Check the user is valid
1219          if ( $this->auth_readonly ) {
1220              $user = $this->authenticate( $username, $password );
1221          }
1222  
1223          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicCount' );
1224  
1225          // If an error was raised by authentication or by an action then return it
1226          if ( $this->error ) {
1227              return $this->error;
1228          }
1229  
1230          // Can be numeric id or slug
1231          if ( isset( $args[2] ) && $forum_id = $args[2] ) {
1232              // Check for bad data
1233              if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) {
1234                  $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) );
1235                  return $this->error;
1236              }
1237              // Check the requested forum exists
1238              if ( !$forum = bb_get_forum( $forum_id ) ) {
1239                  $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) );
1240                  return $this->error;
1241              }
1242  
1243              // OK, let's trust the count in the forum table
1244              $count = (int) $forum->topics;
1245          } else {
1246              // Get all forums
1247              $forums = bb_get_forums();
1248      
1249              // Return an error when no forums exist
1250              if ( !$forums ) {
1251                  $this->error = new IXR_Error( 400, __( 'No forums found.' ) );
1252                  return $this->error;
1253              }
1254  
1255              // Count the topics
1256              $count = 0;
1257              foreach ( $forums as $forum ) {
1258                  $count += (int) $forum->topics;
1259              }
1260          }
1261  
1262          do_action( 'bb_xmlrpc_call_return', 'bb.getTopicCount' );
1263  
1264          // Return the count of topics
1265          return $count;
1266      }
1267  
1268      /**
1269       * Returns details of the latest topics
1270       *
1271       * @since 1.0
1272       * @return array|object The topics when successfully executed or an IXR_Error object on failure
1273       * @param array $args Arguments passed by the XML-RPC call
1274       * @param string $args[0] The username for authentication
1275       * @param string $args[1] The password for authentication
1276       * @param integer|string $args[2] The forum id or slug (optional)
1277       * @param integer $args[3] The number of topics to return (optional)
1278       * @param integer $args[4] The number of the page to return (optional)
1279       *
1280       * XML-RPC request to get all topics in the bbPress instance
1281       * <methodCall>
1282       *     <methodName>bb.getTopics</methodName>
1283       *     <params>
1284       *         <param><value><string>joeblow</string></value></param>
1285       *         <param><value><string>123password</string></value></param>
1286       *     </params>
1287       * </methodCall>
1288       *
1289       * XML-RPC request to get all topics in the forum with id number 34
1290       * <methodCall>
1291       *     <methodName>bb.getTopics</methodName>
1292       *     <params>
1293       *         <param><value><string>joeblow</string></value></param>
1294       *         <param><value><string>123password</string></value></param>
1295       *         <param><value><int>34</int></value></param>
1296       *     </params>
1297       * </methodCall>
1298       *
1299       * XML-RPC request to get topics 6 to 10 in the forum with slug "first-forum"
1300       * <methodCall>
1301       *     <methodName>bb.getTopics</methodName>
1302       *     <params>
1303       *         <param><value><string>joeblow</string></value></param>
1304       *         <param><value><string>123password</string></value></param>
1305       *         <param><value><string>first-forum</string></value></param>
1306       *         <param><value><int>5</int></value></param>
1307       *         <param><value><int>2</int></value></param>
1308       *     </params>
1309       * </methodCall>
1310       */
1311  	function bb_getTopics( $args )
1312      {
1313          do_action( 'bb_xmlrpc_call', 'bb.getTopics' );
1314  
1315          // Escape args
1316          $this->escape( $args );
1317  
1318          // Get the login credentials
1319          $username = $args[0];
1320          $password = (string) $args[1];
1321  
1322          // Check the user is valid
1323          if ( $this->auth_readonly ) {
1324              $user = $this->authenticate( $username, $password );
1325          }
1326  
1327          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopics' );
1328  
1329          // If an error was raised by authentication or by an action then return it
1330          if ( $this->error ) {
1331              return $this->error;
1332          }
1333  
1334          // Setup an array to store arguments to pass to get_topics() function
1335          $get_topics_args = array(
1336              'forum' => false,
1337              'number' => false,
1338              'page' => false
1339          );
1340  
1341          // Can be numeric id or slug
1342          if ( isset( $args[2] ) && $forum_id = $args[2] ) {
1343              // Check for bad data
1344              if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) {
1345                  $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) );
1346                  return $this->error;
1347              }
1348              // Check the requested forum exists
1349              if ( !$forum = bb_get_forum( $forum_id ) ) {
1350                  $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) );
1351                  return $this->error;
1352              }
1353  
1354              // The forum id may have been a slug, so make sure it's an integer here
1355              $get_topics_args['forum'] = (int) $forum->forum_id;
1356          }
1357  
1358          // Can only be an integer
1359          if ( isset( $args[3] ) && $number = (int) $args[3] ) {
1360              $get_topics_args['number'] = $number;
1361          }
1362  
1363          // Can only be an integer
1364          if ( isset( $args[4] ) && $page = (int) $args[4] ) {
1365              $get_topics_args['page'] = $page;
1366          }
1367  
1368          // Get the topics
1369          if ( !$topics = get_latest_topics( $get_topics_args ) ) {
1370              $this->error = new IXR_Error( 400, __( 'No topics found.' ) );
1371              return $this->error;
1372          }
1373  
1374          // Only include "safe" data in the array
1375          $_topics = array();
1376          foreach ( $topics as $topic ) {
1377              $_topics[] = $this->prepare_topic( $topic );
1378          }
1379  
1380          do_action( 'bb_xmlrpc_call_return', 'bb.getTopics' );
1381  
1382          // Return the topics
1383          return $_topics;
1384      }
1385  
1386      /**
1387       * Returns details of a topic
1388       *
1389       * @since 1.0
1390       * @return array|object An array containing details of the returned topic when successfully executed or an IXR_Error object on failure
1391       * @param string $args[0] The username for authentication
1392       * @param string $args[1] The password for authentication
1393       * @param integer|string $args[2] The topic's id or slug
1394       *
1395       * XML-RPC request to get the topic with id number 105
1396       * <methodCall>
1397       *     <methodName>bb.getTopic</methodName>
1398       *     <params>
1399       *         <param><value><string>joeblow</string></value></param>
1400       *         <param><value><string>123password</string></value></param>
1401       *         <param><value><int>105</int></value></param>
1402       *     </params>
1403       * </methodCall>
1404       *
1405       * XML-RPC request to get the topic with slug "cheesy-biscuits"
1406       * <methodCall>
1407       *     <methodName>bb.getTopic</methodName>
1408       *     <params>
1409       *         <param><value><string>joeblow</string></value></param>
1410       *         <param><value><string>123password</string></value></param>
1411       *         <param><value><string>cheesy-biscuits</string></value></param>
1412       *     </params>
1413       * </methodCall>
1414       */
1415  	function bb_getTopic( $args )
1416      {
1417          do_action( 'bb_xmlrpc_call', 'bb.getTopic' );
1418  
1419          // Escape args
1420          $this->escape( $args );
1421  
1422          // Get the login credentials
1423          $username = $args[0];
1424          $password = (string) $args[1];
1425  
1426          // Check the user is valid
1427          if ( $this->auth_readonly ) {
1428              $user = $this->authenticate( $username, $password );
1429          }
1430  
1431          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopic' );
1432  
1433          // If an error was raised by authentication or by an action then return it
1434          if ( $this->error ) {
1435              return $this->error;
1436          }
1437  
1438          // Can be numeric id or slug
1439          $topic_id = isset( $args[2] ) ? $args[2] : false;
1440  
1441          // Check for bad data
1442          if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) {
1443              $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
1444              return $this->error;
1445          }
1446  
1447          // Check the requested topic exists
1448          if ( !$topic = get_topic( $topic_id ) ) {
1449              $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
1450              return $this->error;
1451          }
1452  
1453          // Only include "safe" data in the array
1454          $topic = $this->prepare_topic( $topic );
1455  
1456          do_action( 'bb_xmlrpc_call_return', 'bb.getTopic' );
1457  
1458          // Return the topic
1459          return $topic;
1460      }
1461  
1462      /**
1463       * Creates a new topic
1464       *
1465       * @since 1.0
1466       * @return array|object The topic data when successfully created or an IXR_Error object on failure
1467       * @param array $args Arguments passed by the XML-RPC call
1468       * @param string $args[0] The username for authentication
1469       * @param string $args[1] The password for authentication
1470       * @param array $args[2] The values for the various parameters in the new topic
1471       * @param string $args[2]['title'] The title of the topic
1472       * @param string $args[2]['text'] The text of the topic
1473       * @param integer|string $args[2]['forum_id'] The unique id of the forum which will contain this topic, slugs are OK to use too
1474       * @param string|array $args[2]['tags'] A comma delimited string or an array of tags to add to the topic (optional)
1475       *
1476       * XML-RPC request to create a new topic called "Insane monkeys" inside the forum with id 2
1477       * <methodCall>
1478       *     <methodName>bb.newTopic</methodName>
1479       *     <params>
1480       *         <param><value><string>joeblow</string></value></param>
1481       *         <param><value><string>123password</string></value></param>
1482       *         <param><value><struct>
1483       *             <member>
1484       *                 <name>title</name>
1485       *                 <value><string>Insane monkeys</string></value>
1486       *             </member>
1487       *             <member>
1488       *                 <name>text</name>
1489       *                 <value><string>I just saw some insane monkeys eating bananas, did anyone else see that?</string></value>
1490       *             </member>
1491       *             <member>
1492       *                 <name>forum_id</name>
1493       *                 <value><integer>2</integer></value>
1494       *             </member>
1495       *             <member>
1496       *                 <name>tags</name>
1497       *                 <value><string>monkeys, bananas</string></value>
1498       *             </member>
1499       *         </struct></value></param>
1500       *     </params>
1501       * </methodCall>
1502       */
1503  	function bb_newTopic( $args )
1504      {
1505          do_action( 'bb_xmlrpc_call', 'bb.newTopic' );
1506  
1507          // Escape args
1508          $this->escape( $args );
1509  
1510          // Get the login credentials
1511          $username = $args[0];
1512          $password = (string) $args[1];
1513  
1514          // Check the user is valid
1515          $user = $this->authenticate( $username, $password, 'write_topics', __( 'You do not have permission to write topics.' ) );
1516  
1517          // Additionally they need to be able to write posts
1518          if ( !$this->error && !bb_current_user_can( 'write_posts' ) ) {
1519              $this->error = new IXR_Error( 403, __( 'You do not have permission to write posts.' ) );
1520          }
1521  
1522          do_action( 'bb_xmlrpc_call_authenticated', 'bb.newTopic' );
1523  
1524          // If an error was raised by authentication or by an action then return it
1525          if ( $this->error ) {
1526              return $this->error;
1527          }
1528  
1529          // Make sure there is something for us to do
1530          if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) {
1531              $this->error = new IXR_Error( 400, __( 'The topic data is invalid.' ) );
1532              return $this->error;
1533          }
1534  
1535          $structure = (array) $args[2];
1536  
1537          // Can be numeric id or slug
1538          $forum_id = isset( $structure['forum_id'] ) ? $structure['forum_id'] : false;
1539  
1540          // Check for bad data
1541          if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) {
1542              $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) );
1543              return $this->error;
1544          }
1545  
1546          // Check the requested forum exists
1547          if ( !$forum = bb_get_forum( $forum_id ) ) {
1548              $this->error = new IXR_Error( 400, __( 'No forum found.' ) );
1549              return $this->error;
1550          }
1551  
1552          // The forum id may have been a slug, so make sure it's an integer here
1553          $forum_id = (int) $forum->forum_id;
1554  
1555          // Make sure they are allowed to write topics to this forum
1556          if ( !bb_current_user_can( 'write_topic', $forum_id ) ) {
1557              $this->error = new IXR_Error( 403, __( 'You do not have permission to write topics to this forum.' ) );
1558              return $this->error;
1559          }
1560  
1561          // The topic requires a title
1562          if ( !isset( $structure['title'] ) || !$structure['title'] ) {
1563              $this->error = new IXR_Error( 400, __( 'The topic title is invalid.' ) );
1564              return $this->error;
1565          }
1566  
1567          // The topic requires text
1568          if ( !isset( $structure['text'] ) || !$structure['text'] ) {
1569              $this->error = new IXR_Error( 400, __( 'The topic text is invalid.' ) );
1570              return $this->error;
1571          }
1572  
1573          // Inject structure into an array suitable for bb_insert_topic()
1574          $bb_insert_topic_args = array(
1575              'topic_title' => (string) $structure['title'],
1576              'forum_id' => $forum_id,
1577              'tags' => (string) trim( $structure['tags'] )
1578          );
1579  
1580          // Remove empty settings so that changes to the defaults in bb_insert_topic() are honoured
1581          $bb_insert_topic_args = array_filter( $bb_insert_topic_args );
1582  
1583          // Create the topic
1584          if ( !$topic_id = bb_insert_topic( $bb_insert_topic_args ) ) {
1585              $this->error = new IXR_Error( 500, __( 'The topic could not be created.' ) );
1586              return $this->error;
1587          }
1588  
1589          // Inject structure into an array suitable for bb_insert_post()
1590          $bb_insert_post_args = array(
1591              'topic_id' => (int) $topic_id,
1592              'post_text' => (string) $structure['text']
1593          );
1594  
1595          // Create the post
1596          if ( !$post_id = bb_insert_post( $bb_insert_post_args ) ) {
1597              $this->error = new IXR_Error( 500, __( 'The post could not be created.' ) );
1598              return $this->error;
1599          }
1600  
1601          // Only include "safe" data in the array
1602          $topic = $this->prepare_topic( get_topic( $topic_id ) );
1603  
1604          do_action( 'bb_xmlrpc_call_return', 'bb.newTopic' );
1605  
1606          return $topic;
1607      }
1608  
1609      /**
1610       * Edits an existing topic
1611       *
1612       * @since 1.0
1613       * @return array|object The topic data when successfully edited or an IXR_Error object on failure
1614       * @param array $args Arguments passed by the XML-RPC call
1615       * @param string $args[0] The username for authentication
1616       * @param string $args[1] The password for authentication
1617       * @param array $args[2] The values for the various parameters in the edited topic
1618       * @param integer|string $args[2]['topic_id'] The topic's id or slug
1619       * @param string $args[2]['title'] The title of the topic
1620       * @param string $args[2]['text'] The text of the topic
1621       *
1622       * XML-RPC request to edit the title of a topic with the slug "insane-monkeys"
1623       * <methodCall>
1624       *     <methodName>bb.editTopic</methodName>
1625       *     <params>
1626       *         <param><value><string>joeblow</string></value></param>
1627       *         <param><value><string>123password</string></value></param>
1628       *         <param><value><struct>
1629       *             <member>
1630       *                 <name>topic_id</name>
1631       *                 <value><string>insane-monkeys</string></value>
1632       *             </member>
1633       *             <member>
1634       *                 <name>title</name>
1635       *                 <value><string>Very insane monkeys</string></value>
1636       *             </member>
1637       *         </struct></value></param>
1638       *     </params>
1639       * </methodCall>
1640       */
1641  	function bb_editTopic( $args )
1642      {
1643          do_action( 'bb_xmlrpc_call', 'bb.editTopic' );
1644  
1645          // Escape args
1646          $this->escape( $args );
1647  
1648          // Get the login credentials
1649          $username = $args[0];
1650          $password = (string) $args[1];
1651  
1652          // Check the user is valid
1653          $user = $this->authenticate( $username, $password, 'edit_topics', __( 'You do not have permission to edit topics.' ) );
1654  
1655          // Additionally they need to be able to edit posts
1656          if ( !$this->error && !bb_current_user_can( 'edit_posts' ) ) {
1657              $this->error = new IXR_Error( 403, __( 'You do not have permission to edit posts.' ) );
1658          }
1659  
1660          do_action( 'bb_xmlrpc_call_authenticated', 'bb.editTopic' );
1661  
1662          // If an error was raised by authentication or by an action then return it
1663          if ( $this->error ) {
1664              return $this->error;
1665          }
1666  
1667          // Make sure there is something for us to do
1668          if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) {
1669              $this->error = new IXR_Error( 400, __( 'The topic data is invalid.' ) );
1670              return $this->error;
1671          }
1672  
1673          $structure = (array) $args[2];
1674  
1675          // Can be numeric id or slug
1676          $topic_id = isset( $structure['topic_id'] ) ? $structure['topic_id'] : false;
1677  
1678          // Check for bad data
1679          if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) {
1680              $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
1681              return $this->error;
1682          }
1683  
1684          // Check the requested topic exists
1685          if ( !$topic = get_topic( $topic_id ) ) {
1686              $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
1687              return $this->error;
1688          }
1689  
1690          // The topic id may have been a slug, so make sure it's an integer here
1691          $topic_id = (int) $topic->topic_id;
1692  
1693          // Make sure they are allowed to edit this topic
1694          if ( !bb_current_user_can( 'edit_topic', $topic_id ) ) {
1695              $this->error = new IXR_Error( 403, __( 'You do not have permission to edit this topic.' ) );
1696              return $this->error;
1697          }
1698  
1699          // Get the first post in the topic (that's where the content is)
1700          if ( !$post = bb_get_first_post( $topic_id ) ) {
1701              $this->error = new IXR_Error( 400, __( 'No posts found.' ) );
1702              return $this->error;
1703          }
1704  
1705          $post_id = (int) $post->post_id;
1706  
1707          // Make sure they are allowed to edit this post
1708          if ( !bb_current_user_can( 'edit_post', $post_id ) ) {
1709              $this->error = new IXR_Error( 403, __( 'You do not have permission to edit this post.' ) );
1710              return $this->error;
1711          }
1712  
1713          // The topic requires a title
1714          if ( isset( $structure['title'] ) && !$structure['title'] ) {
1715              $this->error = new IXR_Error( 400, __( 'The topic title is invalid.' ) );
1716              return $this->error;
1717          }
1718  
1719          // The topic requires text
1720          if ( isset( $structure['text'] ) && !$structure['text'] ) {
1721              $this->error = new IXR_Error( 400, __( 'The topic text is invalid.' ) );
1722              return $this->error;
1723          }
1724  
1725          if ( $structure['title'] ) {
1726              if ( !bb_insert_topic( array( 'topic_title' => (string) $structure['title'], 'topic_id' => $topic_id ) ) ) {
1727                  $this->error = new IXR_Error( 500, __( 'The topic could not be edited.' ) );
1728                  return $this->error;
1729              }
1730          }
1731  
1732          if ( $structure['text'] ) {
1733              if ( !bb_insert_post( array( 'post_text' => (string) $structure['text'], 'post_id' => $post_id, 'topic_id'=> $topic_id ) ) ) {
1734                  $this->error = new IXR_Error( 500, __( 'The post could not be edited.' ) );
1735                  return $this->error;
1736              }
1737          }
1738  
1739          // Only include "safe" data in the array
1740          $topic = $this->prepare_topic( get_topic( $topic_id ) );
1741  
1742          do_action( 'bb_xmlrpc_call_return', 'bb.editTopic' );
1743  
1744          return $topic;
1745      }
1746  
1747      /**
1748       * Deletes a topic
1749       *
1750       * @since 1.0
1751       * @return integer|object 0 if already changed, 1 when successfully changed or an IXR_Error object on failure
1752       * @param array $args Arguments passed by the XML-RPC call
1753       * @param string $args[0] The username for authentication
1754       * @param string $args[1] The password for authentication
1755       * @param integer|string $args[2] The unique id of the topic to be deleted
1756       * @param integer $args[3] 1 deletes the topic, 0 undeletes the topic
1757       *
1758       * XML-RPC request to delete a topic with id of 34
1759       * <methodCall>
1760       *     <methodName>bb.deleteTopic</methodName>
1761       *     <params>
1762       *         <param><value><string>joeblow</string></value></param>
1763       *         <param><value><string>123password</string></value></param>
1764       *         <param><value><integer>34</integer></value></param>
1765       *     </params>
1766       * </methodCall>
1767       */
1768  	function bb_deleteTopic( $args )
1769      {
1770          do_action( 'bb_xmlrpc_call', 'bb.deleteTopic' );
1771  
1772          // Escape args
1773          $this->escape( $args );
1774  
1775          // Get the login credentials
1776          $username = $args[0];
1777          $password = (string) $args[1];
1778  
1779          // Check the user is valid
1780          $user = $this->authenticate( $username, $password, 'delete_topics', __( 'You do not have permission to delete topics.' ) );
1781  
1782          do_action( 'bb_xmlrpc_call_authenticated', 'bb.deleteTopic' );
1783  
1784          // If an error was raised by authentication or by an action then return it
1785          if ( $this->error ) {
1786              return $this->error;
1787          }
1788  
1789          // Can be numeric id or slug
1790          $topic_id = isset( $args[2] ) ? $args[2] : false;
1791  
1792          // Check for bad data
1793          if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) {
1794              $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
1795              return $this->error;
1796          }
1797  
1798          // Check the requested topic exists
1799          if ( !$topic = get_topic( $topic_id ) ) {
1800              $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
1801              return $this->error;
1802          }
1803  
1804          // The topic id may have been a slug, so make sure it's an integer here
1805          $topic_id = (int) $topic->topic_id;
1806  
1807          $delete = isset( $args[3] ) ? (int) $args[3] : 1;
1808  
1809          // Don't do anything if already set that way
1810          if ( $delete === (int) $topic->topic_status ) {
1811              return 0;
1812          }
1813  
1814          // Make sure they are allowed to delete this topic
1815          if ( !bb_current_user_can( 'delete_topic', $topic_id ) ) {
1816              $this->error = new IXR_Error( 403, __( 'You do not have permission to delete this topic.' ) );
1817              return $this->error;
1818          }
1819  
1820          // Delete the topic
1821          if ( !bb_delete_topic( $topic_id, $delete ) ) {
1822              $this->error = new IXR_Error( 500, __( 'The topic could not be deleted.' ) );
1823              return $this->error;
1824          }
1825  
1826          $result = 1;
1827  
1828          do_action( 'bb_xmlrpc_call_return', 'bb.deleteTopic' );
1829  
1830          return $result;
1831      }
1832  
1833      /**
1834       * Moves a topic to a different forum
1835       *
1836       * @since 1.0
1837       * @return integer|object the forum id where the topic lives after the method is called or an IXR_Error object on failure
1838       * @param array $args Arguments passed by the XML-RPC call
1839       * @param string $args[0] The username for authentication
1840       * @param string $args[1] The password for authentication
1841       * @param integer|string $args[2] The unique id of the topic to be moved
1842       * @param integer|string $args[3] The unique id of the forum to be moved to
1843       *
1844       * XML-RPC request to move the topic with id of 34 to forum with slug of "better-forum"
1845       * <methodCall>
1846       *     <methodName>bb.moveTopic</methodName>
1847       *     <params>
1848       *         <param><value><string>joeblow</string></value></param>
1849       *         <param><value><string>123password</string></value></param>
1850       *         <param><value><integer>34</integer></value></param>
1851       *         <param><value><string>better-forum</string></value></param>
1852       *     </params>
1853       * </methodCall>
1854       */
1855  	function bb_moveTopic( $args )
1856      {
1857          do_action( 'bb_xmlrpc_call', 'bb.moveTopic' );
1858  
1859          // Escape args
1860          $this->escape( $args );
1861  
1862          // Get the login credentials
1863          $username = $args[0];
1864          $password = (string) $args[1];
1865  
1866          // Check the user is valid
1867          $user = $this->authenticate( $username, $password, 'move_topics', __( 'You do not have permission to move topics.' ) );
1868  
1869          do_action( 'bb_xmlrpc_call_authenticated', 'bb.moveTopic' );
1870  
1871          // If an error was raised by authentication or by an action then return it
1872          if ( $this->error ) {
1873              return $this->error;
1874          }
1875  
1876          // Can be numeric id or slug
1877          $topic_id = isset( $args[2] ) ? $args[2] : false;
1878  
1879          // Check for bad data
1880          if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) {
1881              $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
1882              return $this->error;
1883          }
1884  
1885          // Check the requested topic exists
1886          if ( !$topic = get_topic( $topic_id ) ) {
1887              $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
1888              return $this->error;
1889          }
1890  
1891          // The topic id may have been a slug, so make sure it's an integer here
1892          $topic_id = (int) $topic->topic_id;
1893  
1894          // Can be numeric id or slug
1895          $forum_id = isset( $args[3] ) ? $args[3] : false;
1896  
1897          // Check for bad data
1898          if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) {
1899              $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) );
1900              return $this->error;
1901          }
1902  
1903          // Check the requested topic exists
1904          if ( !$forum = bb_get_forum( $forum_id ) ) {
1905              $this->error = new IXR_Error( 400, __( 'No forum found.' ) );
1906              return $this->error;
1907          }
1908  
1909          // The forum id may have been a slug, so make sure it's an integer here
1910          $forum_id = (int) $forum->forum_id;
1911  
1912          // Only move it if it isn't already there
1913          if ( $forum_id !== (int) $topic->forum_id ) {
1914              // Make sure they are allowed to move this topic specifically to this forum
1915              if ( !bb_current_user_can( 'move_topic', $topic_id, $forum_id ) ) {
1916                  $this->error = new IXR_Error( 403, __( 'You are not allowed to move this topic to this forum.' ) );
1917                  return $this->error;
1918              }
1919  
1920              // Move the topic
1921              if ( !bb_move_topic( $topic_id, $forum_id ) ) {
1922                  $this->error = new IXR_Error( 500, __( 'The topic could not be moved.' ) );
1923                  return $this->error;
1924              }
1925          }
1926  
1927          do_action( 'bb_xmlrpc_call_return', 'bb.moveTopic' );
1928  
1929          return $forum_id;
1930      }
1931  
1932      /**
1933       * Sticks a topic to the top of a forum or the front page
1934       *
1935       * @since 1.0
1936       * @return integer|object 0 if it is already stuck to the desired location, 1 when successfully stuck or an IXR_Error object on failure
1937       * @param array $args Arguments passed by the XML-RPC call
1938       * @param string $args[0] The username for authentication
1939       * @param string $args[1] The password for authentication
1940       * @param integer|string $args[2] The unique id of the topic to be stuck
1941       * @param integer $args[3] 0 unsticks, 1 sticks, 2 sticks to front (optional)
1942       *
1943       * XML-RPC request to stick the topic with id of 34 to the front page
1944       * <methodCall>
1945       *     <methodName>bb.stickTopic</methodName>
1946       *     <params>
1947       *         <param><value><string>joeblow</string></value></param>
1948       *         <param><value><string>123password</string></value></param>
1949       *         <param><value><integer>34</integer></value></param>
1950       *         <param><value><integer>1</integer></value></param>
1951       *     </params>
1952       * </methodCall>
1953       */
1954  	function bb_stickTopic( $args )
1955      {
1956          do_action( 'bb_xmlrpc_call', 'bb.stickTopic' );
1957  
1958          // Escape args
1959          $this->escape( $args );
1960  
1961          // Get the login credentials
1962          $username = $args[0];
1963          $password = (string) $args[1];
1964  
1965          // Check the user is valid
1966          $user = $this->authenticate( $username, $password, 'stick_topics', __( 'You do not have permission to stick topics.' ) );
1967  
1968          do_action( 'bb_xmlrpc_call_authenticated', 'bb.stickTopic' );
1969  
1970          // If an error was raised by authentication or by an action then return it
1971          if ( $this->error ) {
1972              return $this->error;
1973          }
1974  
1975          // Can be numeric id or slug
1976          $topic_id = isset( $args[2] ) ? $args[2] : false;
1977  
1978          // Check for bad data
1979          if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) {
1980              $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
1981              return $this->error;
1982          }
1983  
1984          // Check the requested topic exists
1985          if ( !$topic = get_topic( $topic_id ) ) {
1986              $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
1987              return $this->error;
1988          }
1989  
1990          // The topic id may have been a slug, so make sure it's an integer here
1991          $topic_id = (int) $topic->topic_id;
1992  
1993          // Make sure they are allowed to stick this topic
1994          if ( !bb_current_user_can( 'stick_topic', $topic_id ) ) {
1995              $this->error = new IXR_Error( 403, __( 'You do not have permission to stick this topic.' ) );
1996              return $this->error;
1997          }
1998  
1999          // Stick to where?
2000          $where = isset( $args[3] ) ? (int) $args[3] : 1;
2001  
2002          // Forget it if it's already there
2003          if ( $where === (int) $topic->topic_sticky ) {
2004              return 0;
2005          }
2006  
2007          // Stick the topic
2008          if ( !bb_stick_topic( $topic_id, $where ) ) {
2009              $this->error = new IXR_Error( 500, __( 'The topic could not be stuck.' ) );
2010              return $this->error;
2011          }
2012  
2013          $result = 1;
2014  
2015          do_action( 'bb_xmlrpc_call_return', 'bb.stickTopic' );
2016  
2017          return $result;
2018      }
2019  
2020  
2021  
2022      /**
2023       * Closes a topic
2024       *
2025       * @since 1.0
2026       * @return integer|object 0 when already changed, 1 when successfully changed or an IXR_Error object on failure
2027       * @param array $args Arguments passed by the XML-RPC call
2028       * @param string $args[0] The username for authentication
2029       * @param string $args[1] The password for authentication
2030       * @param integer|string $args[2] The unique id of the topic to be closed
2031       * @param integer $args[2] 0 closes, 1 opens (optional)
2032       *
2033       * XML-RPC request to close the topic with slug of "really-old-topic"
2034       * <methodCall>
2035       *     <methodName>bb.closeTopic</methodName>
2036       *     <params>
2037       *         <param><value><string>joeblow</string></value></param>
2038       *         <param><value><string>123password</string></value></param>
2039       *         <param><value><string>really-old-topic</string></value></param>
2040       *     </params>
2041       * </methodCall>
2042       *
2043       * XML-RPC request to open the topic with slug of "really-old-topic"
2044       * <methodCall>
2045       *     <methodName>bb.closeTopic</methodName>
2046       *     <params>
2047       *         <param><value><string>joeblow</string></value></param>
2048       *         <param><value><string>123password</string></value></param>
2049       *         <param><value><string>really-old-topic</string></value></param>
2050       *         <param><value><integer>1</integer></value></param>
2051       *     </params>
2052       * </methodCall>
2053       */
2054  	function bb_closeTopic( $args )
2055      {
2056          do_action( 'bb_xmlrpc_call', 'bb.closeTopic' );
2057  
2058          // Escape args
2059          $this->escape( $args );
2060  
2061          // Get the login credentials
2062          $username = $args[0];
2063          $password = (string) $args[1];
2064  
2065          // Check the user is valid
2066          $user = $this->authenticate( $username, $password, 'close_topics', __( 'You do not have permission to close topics.' ) );
2067  
2068          do_action( 'bb_xmlrpc_call_authenticated', 'bb.closeTopic' );
2069  
2070          // If an error was raised by authentication or by an action then return it
2071          if ( $this->error ) {
2072              return $this->error;
2073          }
2074  
2075          // Can be numeric id or slug
2076          $topic_id = isset( $args[2] ) ? $args[2] : false;
2077  
2078          // Check for bad data
2079          if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) {
2080              $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
2081              return $this->error;
2082          }
2083  
2084          // Check the requested topic exists
2085          if ( !$topic = get_topic( $topic_id ) ) {
2086              $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
2087              return $this->error;
2088          }
2089  
2090          // The topic id may have been a slug, so make sure it's an integer here
2091          $topic_id = (int) $topic->topic_id;
2092  
2093          // Make sure they are allowed to close this topic
2094          if ( !bb_current_user_can( 'close_topic', $topic_id ) ) {
2095              $this->error = new IXR_Error( 403, __( 'You do not have permission to close this topic.' ) );
2096              return $this->error;
2097          }
2098  
2099          // Open or close?
2100          $close = isset( $args[3] ) ? (int) $args[3] : 0;
2101  
2102          // Forget it if it's already matching
2103          if ( $close === (int) $topic->topic_open ) {
2104              return 0;
2105          }
2106  
2107          // Close the topic
2108          if ( !$close && !bb_close_topic( $topic_id ) ) {
2109              $this->error = new IXR_Error( 500, __( 'The topic could not be closed.' ) );
2110              return $this->error;
2111          }
2112  
2113          // Open the topic
2114          if ( $close && !bb_open_topic( $topic_id ) ) {
2115              $this->error = new IXR_Error( 500, __( 'The topic could not be opened.' ) );
2116              return $this->error;
2117          }
2118  
2119          $result = 1;
2120  
2121          do_action( 'bb_xmlrpc_call_return', 'bb.closeTopic' );
2122  
2123          return $result;
2124      }
2125  
2126  
2127  
2128      /**
2129       * bbPress publishing API - Post XML-RPC methods
2130       */
2131  
2132      /**
2133       * Returns a numerical count of posts
2134       *
2135       * @since 1.0
2136       * @return integer|object The number of topics when successfully executed or an IXR_Error object on failure
2137       * @param array $args Arguments passed by the XML-RPC call
2138       * @param string $args[0] The username for authentication
2139       * @param string $args[1] The password for authentication
2140       * @param integer|string $args[2] The topic id or slug
2141       *
2142       * XML-RPC request to get a count of all posts in the topic with slug "countable-topic"
2143       * <methodCall>
2144       *     <methodName>bb.getPostCount</methodName>
2145       *     <params>
2146       *         <param><value><string>joeblow</string></value></param>
2147       *         <param><value><string>123password</string></value></param>
2148       *         <param><value><string>countable-topic</string></value></param>
2149       *     </params>
2150       * </methodCall>
2151       */
2152  	function bb_getPostCount( $args )
2153      {
2154          do_action( 'bb_xmlrpc_call', 'bb.getPostCount' );
2155  
2156          // Escape args
2157          $this->escape( $args );
2158  
2159          // Get the login credentials
2160          $username = $args[0];
2161          $password = (string) $args[1];
2162  
2163          // Check the user is valid
2164          if ( $this->auth_readonly ) {
2165              $user = $this->authenticate( $username, $password );
2166          }
2167  
2168          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getPostCount' );
2169  
2170          // If an error was raised by authentication or by an action then return it
2171          if ( $this->error ) {
2172              return $this->error;
2173          }
2174  
2175          // Can be numeric id or slug
2176          $topic_id = isset( $args[2] ) ? $args[2] : false;
2177  
2178          // Check for bad data
2179          if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) {
2180              $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
2181              return $this->error;
2182          }
2183  
2184          // Check the requested topic exists
2185          if ( !$topic = get_topic( $topic_id ) ) {
2186              $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
2187              return $this->error;
2188          }
2189  
2190          // OK, let's trust the count in the topic table
2191          $count = $topic->topic_posts;
2192  
2193          do_action( 'bb_xmlrpc_call_return', 'bb.getPostCount' );
2194  
2195          // Return the count of posts
2196          return $count;
2197      }
2198  
2199      /**
2200       * Returns details of the posts in a given topic
2201       *
2202       * @since 1.0
2203       * @return array|object The posts when successfully executed or an IXR_Error object on failure
2204       * @param array $args Arguments passed by the XML-RPC call
2205       * @param string $args[0] The username for authentication
2206       * @param string $args[1] The password for authentication
2207       * @param integer|string $args[2] The topic id or slug
2208       * @param integer $args[3] The number of posts to return (optional)
2209       * @param integer $args[4] The number of the page to return (optional)
2210       *
2211       * XML-RPC request to get all posts in the topic with id number 53
2212       * <methodCall>
2213       *     <methodName>bb.getPosts</methodName>
2214       *     <params>
2215       *         <param><value><string>joeblow</string></value></param>
2216       *         <param><value><string>123password</string></value></param>
2217       *         <param><value><int>53</int></value></param>
2218       *     </params>
2219       * </methodCall>
2220       *
2221       * XML-RPC request to get the latest 5 posts in the topic with id number 341
2222       * <methodCall>
2223       *     <methodName>bb.getPosts</methodName>
2224       *     <params>
2225       *         <param><value><string>joeblow</string></value></param>
2226       *         <param><value><string>123password</string></value></param>
2227       *         <param><value><int>341</int></value></param>
2228       *         <param><value><int>5</int></value></param>
2229       *     </params>
2230       * </methodCall>
2231       *
2232       * XML-RPC request to get posts 11 to 20 in the topic with slug "long-topic"
2233       * <methodCall>
2234       *     <methodName>bb.getPosts</methodName>
2235       *     <params>
2236       *         <param><value><string>joeblow</string></value></param>
2237       *         <param><value><string>123password</string></value></param>
2238       *         <param><value><string>long-topic</string></value></param>
2239       *         <param><value><int>10</int></value></param>
2240       *         <param><value><int>2</int></value></param>
2241       *     </params>
2242       * </methodCall>
2243       */
2244  	function bb_getPosts( $args )
2245      {
2246          do_action( 'bb_xmlrpc_call', 'bb.getPosts' );
2247  
2248          // Escape args
2249          $this->escape( $args );
2250  
2251          // Get the login credentials
2252          $username = $args[0];
2253          $password = (string) $args[1];
2254  
2255          // Check the user is valid
2256          if ( $this->auth_readonly ) {
2257              $user = $this->authenticate( $username, $password );
2258          }
2259  
2260          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getPosts' );
2261  
2262          // If an error was raised by authentication or by an action then return it
2263          if ( $this->error ) {
2264              return $this->error;
2265          }
2266  
2267          // Can be numeric id or slug
2268          $topic_id = isset( $args[2] ) ? $args[2] : false;
2269  
2270          // Check for bad data
2271          if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) {
2272              $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
2273              return $this->error;
2274          }
2275  
2276          // Check the requested topic exists
2277          if ( !$topic = get_topic( $topic_id ) ) {
2278              $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
2279              return $this->error;
2280          }
2281  
2282          // The topic id may have been a slug, so make sure it's an integer here
2283          $topic_id = (int) $topic->topic_id;
2284  
2285          // Setup an array to store arguments to pass to get_thread() function
2286          $get_thread_args = array();
2287  
2288          // Can only be an integer
2289          if ( isset( $args[3] ) && $per_page = (int) $args[3] ) {
2290              $get_thread_args['per_page'] = $per_page;
2291          }
2292  
2293          // Can only be an integer
2294          if ( isset( $args[4] ) && $page = (int) $args[4] ) {
2295              $get_thread_args['page'] = $page;
2296          }
2297  
2298          // Get the posts
2299          if ( !$posts = get_thread( $topic_id, $get_thread_args ) ) {
2300              $this->error = new IXR_Error( 500, __( 'No posts found.' ) );
2301              return $this->error;
2302          }
2303  
2304          // Only include "safe" data in the array
2305          $_posts = array();
2306          foreach ( $posts as $post ) {
2307              $_posts[] = $this->prepare_post( $post );
2308          }
2309  
2310          do_action( 'bb_xmlrpc_call_return', 'bb.getPosts' );
2311  
2312          // Return the posts
2313          return $_posts;
2314      }
2315  
2316      /**
2317       * Returns details of a post
2318       *
2319       * @since 1.0
2320       * @return array|object An array containing details of the returned post when successfully executed or an IXR_Error object on failure
2321       * @param array $args Arguments passed by the XML-RPC call
2322       * @param string $args[0] The username for authentication
2323       * @param string $args[1] The password for authentication
2324       * @param integer $args[2] The post's id
2325       *
2326       * XML-RPC request to get the post with id number 32
2327       * <methodCall>
2328       *     <methodName>bb.getPost</methodName>
2329       *     <params>
2330       *         <param><value><string>joeblow</string></value></param>
2331       *         <param><value><string>123password</string></value></param>
2332       *         <param><value><int>32</int></value></param>
2333       *     </params>
2334       * </methodCall>
2335       */
2336  	function bb_getPost( $args )
2337      {
2338          do_action( 'bb_xmlrpc_call', 'bb.getPost' );
2339  
2340          // Escape args
2341          $this->escape( $args );
2342  
2343          // Get the login credentials
2344          $username = $args[0];
2345          $password = (string) $args[1];
2346  
2347          // Check the user is valid
2348          if ( $this->auth_readonly ) {
2349              $user = $this->authenticate( $username, $password );
2350          }
2351  
2352          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getPost' );
2353  
2354          // If an error was raised by authentication or by an action then return it
2355          if ( $this->error ) {
2356              return $this->error;
2357          }
2358  
2359          // Can be numeric id or slug
2360          $post_id = isset( $args[2] ) ? (int) $args[2] : false;
2361  
2362          // Check for bad data
2363          if ( !$post_id ) {
2364              $this->error = new IXR_Error( 400, __( 'The post id is invalid.' ) );
2365              return $this->error;
2366          }
2367  
2368          // Check the requested post exists
2369          if ( !$post = bb_get_post( $post_id ) ) {
2370              $this->error = new IXR_Error( 400, __( 'No post found.' ) );
2371              return $this->error;
2372          }
2373  
2374          // Only include "safe" data in the array
2375          $_post = $this->prepare_post( $post );
2376  
2377          do_action( 'bb_xmlrpc_call_return', 'bb.getPost' );
2378  
2379          // Return the post
2380          return $_post;
2381      }
2382  
2383      /**
2384       * Creates a new post in a given topic
2385       *
2386       * @since 1.0
2387       * @return array|object The post data when successfully created or an IXR_Error object on failure
2388       * @param array $args Arguments passed by the XML-RPC call
2389       * @param string $args[0] The username for authentication
2390       * @param string $args[1] The password for authentication
2391       * @param array $args[2] The values for the various parameters in the new topic
2392       * @param string $args[2]['text'] The text of the topic
2393       * @param integer|string $args[2]['topic_id'] The unique id of the topic which will contain this topic, slugs are OK to use too
2394       *
2395       * XML-RPC request to create a new post in the topic with slug "totally-worth-it"
2396       * <methodCall>
2397       *     <methodName>bb.newPost</methodName>
2398       *     <params>
2399       *         <param><value><string>joeblow</string></value></param>
2400       *         <param><value><string>123password</string></value></param>
2401       *         <param><value><struct>
2402       *             <member>
2403       *                 <name>text</name>
2404       *                 <value><string>I agree, it is totally worth it.</string></value>
2405       *             </member>
2406       *             <member>
2407       *                 <name>topic_id</name>
2408       *                 <value><string>totally-worth-it</string></value>
2409       *             </member>
2410       *         </struct></value></param>
2411       *     </params>
2412       * </methodCall>
2413       */
2414  	function bb_newPost( $args )
2415      {
2416          do_action( 'bb_xmlrpc_call', 'bb.newPost' );
2417  
2418          // Escape args
2419          $this->escape( $args );
2420  
2421          // Get the login credentials
2422          $username = $args[0];
2423          $password = (string) $args[1];
2424  
2425          // Check the user is valid
2426          $user = $this->authenticate( $username, $password, 'write_posts', __( 'You do not have permission to write posts.' ) );
2427  
2428          do_action( 'bb_xmlrpc_call_authenticated', 'bb.newPost' );
2429  
2430          // If an error was raised by authentication or by an action then return it
2431          if ( $this->error ) {
2432              return $this->error;
2433          }
2434  
2435          // Make sure there is something for us to do
2436          if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) {
2437              $this->error = new IXR_Error( 400, __( 'The post data is invalid.' ) );
2438              return $this->error;
2439          }
2440  
2441          $structure = (array) $args[2];
2442  
2443          // Can be numeric id or slug
2444          $topic_id = isset( $structure['topic_id'] ) ? $structure['topic_id'] : false;
2445  
2446          // Check for bad data
2447          if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) {
2448              $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
2449              return $this->error;
2450          }
2451  
2452          // Check the requested topic exists
2453          if ( !$topic = get_topic( $topic_id ) ) {
2454              $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
2455              return $this->error;
2456          }
2457  
2458          // The topic id may have been a slug, so make sure it's an integer here
2459          $topic_id = (int) $topic->topic_id;
2460  
2461          // Make sure they are allowed to write posts to this topic
2462          if ( !bb_current_user_can( 'write_post', $topic_id ) ) {
2463              $this->error = new IXR_Error( 403, __( 'You do not have permission to write posts to this topic.' ) );
2464              return $this->error;
2465          }
2466  
2467          // The post requires text
2468          if ( !isset( $structure['text'] ) || !$structure['text'] ) {
2469              $this->error = new IXR_Error( 400, __( 'The post text is invalid.' ) );
2470              return $this->error;
2471          }
2472  
2473          // Inject structure into an array suitable for bb_insert_post()
2474          $bb_insert_post_args = array(
2475              'topic_id' => $topic_id,
2476              'post_text' => (string) $structure['text']
2477          );
2478  
2479          // Create the post
2480          if ( !$post_id = bb_insert_post( $bb_insert_post_args ) ) {
2481              $this->error = new IXR_Error( 500, __( 'The post could not be created.' ) );
2482              return $this->error;
2483          }
2484  
2485          // Only include "safe" data in the array
2486          $post = $this->prepare_forum( bb_get_post( $post_id ) );
2487  
2488          do_action( 'bb_xmlrpc_call_return', 'bb.newPost' );
2489  
2490          return $post;
2491      }
2492  
2493      /**
2494       * Edits an existing post
2495       *
2496       * @since 1.0
2497       * @return array|object The post data when successfully edited or an IXR_Error object on failure
2498       * @param array $args Arguments passed by the XML-RPC call
2499       * @param string $args[0] The username for authentication
2500       * @param string $args[1] The password for authentication
2501       * @param array $args[2] The values for the various parameters in the new topic
2502       * @param integer $args[2]['post_id'] The unique id of the post
2503       * @param string $args[2]['text'] The text of the topic
2504       *
2505       * XML-RPC request to edit the text of the post with an id of 452
2506       * <methodCall>
2507       *     <methodName>bb.editPost</methodName>
2508       *     <params>
2509       *         <param><value><string>joeblow</string></value></param>
2510       *         <param><value><string>123password</string></value></param>
2511       *         <param><value><struct>
2512       *             <member>
2513       *                 <name>post_id</name>
2514       *                 <value><int>452</int></value>
2515       *             </member>
2516       *             <member>
2517       *                 <name>text</name>
2518       *                 <value><string>For now I will withhold my opinion.</string></value>
2519       *             </member>
2520       *         </struct></value></param>
2521       *     </params>
2522       * </methodCall>
2523       */
2524  	function bb_editPost( $args )
2525      {
2526          do_action( 'bb_xmlrpc_call', 'bb.editPost' );
2527  
2528          // Escape args
2529          $this->escape( $args );
2530  
2531          // Get the login credentials
2532          $username = $args[0];
2533          $password = (string) $args[1];
2534  
2535          // Check the user is valid
2536          $user = $this->authenticate( $username, $password, 'edit_posts', __( 'You do not have permission to edit posts.' ) );
2537  
2538          do_action( 'bb_xmlrpc_call_authenticated', 'bb.editPost' );
2539  
2540          // If an error was raised by authentication or by an action then return it
2541          if ( $this->error ) {
2542              return $this->error;
2543          }
2544  
2545          // Make sure there is something for us to do
2546          if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) {
2547              $this->error = new IXR_Error( 400, __( 'The post data is invalid.' ) );
2548              return $this->error;
2549          }
2550  
2551          $structure = (array) $args[2];
2552  
2553          // Can be numeric id or slug
2554          $post_id = isset( $structure['post_id'] ) ? (int) $structure['post_id'] : false;
2555  
2556          // Check for bad data
2557          if ( !$post_id ) {
2558              $this->error = new IXR_Error( 400, __( 'The post id is invalid.' ) );
2559              return $this->error;
2560          }
2561  
2562          // Check the requested topic exists
2563          if ( !$post = bb_get_post( $post_id ) ) {
2564              $this->error = new IXR_Error( 400, __( 'No post found.' ) );
2565              return $this->error;
2566          }
2567  
2568          // Re-assign the post id
2569          $post_id = (int) $post->post_id;
2570  
2571          // Make sure they are allowed to edit this post
2572          if ( !bb_current_user_can( 'edit_post', $post_id ) ) {
2573              $this->error = new IXR_Error( 403, __( 'You do not have permission to edit this post.' ) );
2574              return $this->error;
2575          }
2576  
2577          // The post requires text
2578          if ( !isset( $structure['text'] ) || !$structure['text'] ) {
2579              $this->error = new IXR_Error( 400, __( 'The post text is invalid.' ) );
2580              return $this->error;
2581          }
2582  
2583          // Inject structure into an array suitable for bb_insert_post()
2584          $bb_insert_post_args = array(
2585              'post_id' => $post_id,
2586              'post_text' => (string) $structure['text']
2587          );
2588  
2589          // Create the post
2590          if ( !$post_id = bb_insert_post( $bb_insert_post_args ) ) {
2591              $this->error = new IXR_Error( 500, __( 'The post could not be edited.' ) );
2592              return $this->error;
2593          }
2594  
2595          // Only include "safe" data in the array
2596          $post = $this->prepare_forum( bb_get_post( $post_id ) );
2597  
2598          do_action( 'bb_xmlrpc_call_return', 'bb.editPost' );
2599  
2600          return $post;
2601      }
2602  
2603      /**
2604       * Deletes an existing post
2605       *
2606       * @since 1.0
2607       * @return integer|object 1 when successfully deleted, 0 when already deleted or an IXR_Error object on failure
2608       * @param array $args Arguments passed by the XML-RPC call
2609       * @param string $args[0] The username for authentication
2610       * @param string $args[1] The password for authentication
2611       * @param array $args[2] The unique id of the post
2612       * @param array $args[3] 1 deletes the post, 0 undeletes the post (optional)
2613       *
2614       * XML-RPC request to delete the post with an id of 4301
2615       * <methodCall>
2616       *     <methodName>bb.editPost</methodName>
2617       *     <params>
2618       *         <param><value><string>joeblow</string></value></param>
2619       *         <param><value><string>123password</string></value></param>
2620       *         <param><value><int>4301</int></value></param>
2621       *     </params>
2622       * </methodCall>
2623       */
2624  	function bb_deletePost( $args )
2625      {
2626          do_action( 'bb_xmlrpc_call', 'bb.deletePost' );
2627  
2628          // Escape args
2629          $this->escape( $args );
2630  
2631          // Get the login credentials
2632          $username = $args[0];
2633          $password = (string) $args[1];
2634  
2635          // Check the user is valid
2636          $user = $this->authenticate( $username, $password, 'delete_posts', __( 'You do not have permission to delete posts.' ) );
2637  
2638          do_action( 'bb_xmlrpc_call_authenticated', 'bb.deletePost' );
2639  
2640          // If an error was raised by authentication or by an action then return it
2641          if ( $this->error ) {
2642              return $this->error;
2643          }
2644  
2645          // Can be numeric id or slug
2646          $post_id = isset( $args[2] ) ? (int) $args[2] : false;
2647  
2648          // Check for bad data
2649          if ( !$post_id ) {
2650              $this->error = new IXR_Error( 400, __( 'The post id is invalid.' ) );
2651              return $this->error;
2652          }
2653  
2654          // Check the requested topic exists
2655          if ( !$post = bb_get_post( $post_id ) ) {
2656              $this->error = new IXR_Error( 400, __( 'No post found.' ) );
2657              return $this->error;
2658          }
2659  
2660          // Re-assign the post id
2661          $post_id = (int) $post->post_id;
2662  
2663          // Make sure they are allowed to delete this post
2664          if ( !bb_current_user_can( 'delete_post', $post_id ) ) {
2665              $this->error = new IXR_Error( 403, __( 'You do not have permission to delete this post.' ) );
2666              return $this->error;
2667          }
2668  
2669          $status = isset( $args[3] ) ? (int) $args[3] : 1;
2670  
2671          if ( $status === (int) $post->post_status ) {
2672              return 0;
2673          }
2674  
2675          // Delete the post
2676          if ( !$post_id = bb_delete_post( $post_id, $status ) ) {
2677              $this->error = new IXR_Error( 500, __( 'The post could not be edited.' ) );
2678              return $this->error;
2679          }
2680  
2681          $result = 1;
2682  
2683          do_action( 'bb_xmlrpc_call_return', 'bb.deletePost' );
2684  
2685          return $result;
2686      }
2687  
2688  
2689  
2690      /**
2691       * bbPress publishing API - Topic Tag XML-RPC methods
2692       */
2693  
2694      /**
2695       * Returns the hot tags in order of hotness in a given forum or all hot tags
2696       *
2697       * @since 1.0
2698       * @return integer|object The tag data when successfully executed or an IXR_Error object on failure
2699       * @param array $args Arguments passed by the XML-RPC call
2700       * @param string $args[0] The username for authentication
2701       * @param string $args[1] The password for authentication
2702       * @param integer $args[2] The number of tags to return (optional)
2703       * @param integer|string $args[3] The forum id or slug (optional)
2704       *
2705       * XML-RPC request to get the 20 hottest tags in the forum with slug "hawtness"
2706       * <methodCall>
2707       *     <methodName>bb.getTopicTags</methodName>
2708       *     <params>
2709       *         <param><value><string>joeblow</string></value></param>
2710       *         <param><value><string>123password</string></value></param>
2711       *         <param><value><int>20</int></value></param>
2712       *         <param><value><string>hawtness</string></value></param>
2713       *     </params>
2714       * </methodCall>
2715       */
2716  	function bb_getHotTopicTags( $args )
2717      {
2718          do_action( 'bb_xmlrpc_call', 'bb.getHotTopicTags' );
2719  
2720          // Escape args
2721          $this->escape( $args );
2722  
2723          // Get the login credentials
2724          $username = $args[0];
2725          $password = (string) $args[1];
2726  
2727          // Check the user is valid
2728          if ( $this->auth_readonly ) {
2729              $user = $this->authenticate( $username, $password );
2730          }
2731  
2732          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getHotTopicTags' );
2733  
2734          // If an error was raised by authentication or by an action then return it
2735          if ( $this->error ) {
2736              return $this->error;
2737          }
2738  
2739          // Must be a number
2740          $per_page = isset( $args[2] ) ? (integer) $args[2] : false;
2741  
2742          // Can be numeric id or slug
2743          $forum_id = isset( $args[3] ) ? $args[3] : false;
2744  
2745          if ( $forum_id ) {
2746              // Check for bad data
2747              if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) {
2748                  $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) );
2749                  return $this->error;
2750              }
2751  
2752              // Check the requested forum exists
2753              if ( !$forum = bb_get_forum( $forum_id ) ) {
2754                  $this->error = new IXR_Error( 404, __( 'No forum found.' ) );
2755                  return $this->error;
2756              }
2757  
2758              global $bbdb;
2759              $topic_ids = $bbdb->get_col( $bbdb->prepare( "SELECT topic_id FROM `" . $bbdb->topics . "` WHERE `topic_status` = 0 AND `topic_open` = 1 AND `tag_count` > 0 AND `forum_id` = %s;", $forum_id ) );
2760  
2761              if ( !count( $topic_ids ) ) {
2762                  $this->error = new IXR_Error( 400, __( 'No topics found.' ) );
2763                  return $this->error;
2764              }
2765  
2766              global $wp_taxonomy_object;
2767              $tags = $wp_taxonomy_object->get_object_terms( $topic_ids, 'bb_topic_tag', array( 'fields' => 'all_with_object_id', 'orderby' => 'count', 'order' => 'DESC' ) );
2768  
2769              if ( !$tags || is_wp_error( $tags ) ) {
2770                  $this->error = new IXR_Error( 500, __( 'Could not retrieve hot topic tags.' ) );
2771                  return $this->error;
2772              }
2773              if ( !count( $tags ) ) {
2774                  $this->error = new IXR_Error( 500, __( 'No hot topic tags found.' ) );
2775                  return $this->error;
2776              }
2777              global $bb_log;
2778              $bb_log->debug($tags);
2779  
2780              for ( $i = 0; isset( $tags[$i] ); $i++ ) {
2781                  _bb_make_tag_compat( $tags[$i] );
2782              }
2783              $bb_log->debug($tags);
2784  
2785              // Only include "safe" data in the array
2786              $_tags = array();
2787              foreach ( $tags as $tag ) {
2788                  $_tag = $this->prepare_topic_tag( $tag );
2789                  if ( !in_array( $_tag, $_tags ) ) {
2790                      $_tags[] = $_tag;
2791                  }
2792              }
2793  
2794              if ( $per_page ) {
2795                  $_tags = array_slice( $_tags, 0, $per_page );
2796              }
2797          } else {
2798              if ( !$tags = bb_get_top_tags( array( 'get' => 'all', 'number' => $per_page ) ) ) {
2799                  $this->error = new IXR_Error( 500, __( 'No hot topic tags found.' ) );
2800                  return $this->error;
2801              }
2802  
2803              // Only include "safe" data in the array
2804              $_tags = array();
2805              foreach ( $tags as $tag ) {
2806                  $_tags[] = $this->prepare_topic_tag( $tag );
2807              }
2808          }
2809  
2810          do_action( 'bb_xmlrpc_call', 'bb.getHotTopicTags' );
2811  
2812          return $_tags;
2813      }
2814  
2815      /**
2816       * Returns a numerical count of tags in a given topic or all tags
2817       *
2818       * @since 1.0
2819       * @return integer|object The number of topics when successfully executed or an IXR_Error object on failure
2820       * @param array $args Arguments passed by the XML-RPC call
2821       * @param string $args[0] The username for authentication
2822       * @param string $args[1] The password for authentication
2823       * @param integer|string $args[2] The topic id or slug (optional)
2824       *
2825       * XML-RPC request to get a count of all tags in the topic with slug "woot-frist-topic"
2826       * <methodCall>
2827       *     <methodName>bb.getTopicTagCount</methodName>
2828       *     <params>
2829       *         <param><value><string>joeblow</string></value></param>
2830       *         <param><value><string>123password</string></value></param>
2831       *         <param><value><string>woot-frist-topic</string></value></param>
2832       *     </params>
2833       * </methodCall>
2834       */
2835  	function bb_getTopicTagCount( $args )
2836      {
2837          do_action( 'bb_xmlrpc_call', 'bb.getTopicTagCount' );
2838  
2839          // Escape args
2840          $this->escape( $args );
2841  
2842          // Get the login credentials
2843          $username = $args[0];
2844          $password = (string) $args[1];
2845  
2846          // Check the user is valid
2847          if ( $this->auth_readonly ) {
2848              $user = $this->authenticate( $username, $password );
2849          }
2850  
2851          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicTagCount' );
2852  
2853          // If an error was raised by authentication or by an action then return it
2854          if ( $this->error ) {
2855              return $this->error;
2856          }
2857  
2858          // Can be numeric id or slug
2859          $topic_id = isset( $args[2] ) ? $args[2] : false;
2860  
2861          // Check for bad data
2862          if ( $topic_id ) {
2863              if ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) {
2864                  $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
2865                  return $this->error;
2866              }
2867  
2868              // Check the requested topic exists
2869              if ( !$topic = get_topic( $topic_id ) ) {
2870                  $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
2871                  return $this->error;
2872              }
2873  
2874              // The topic id may have been a slug, so make sure it's an integer here
2875              $topic_id = (int) $topic->topic_id;
2876  
2877              // Now get the tags
2878              if ( !$tags = bb_get_topic_tags( $topic_id ) ) {
2879                  $tags = array();
2880              }
2881  
2882              // Count the tags
2883              $count = count( $tags );
2884          } else {
2885              global $wp_taxonomy_object;
2886              $count = $wp_taxonomy_object->count_terms( 'bb_topic_tag' );
2887              if ( is_wp_error( $count ) ) {
2888                  $this->error = new IXR_Error( 500, __( 'Could not get a count of all topic tags.' ) );
2889                  return $this->error;
2890              }
2891          }
2892  
2893          do_action( 'bb_xmlrpc_call_return', 'bb.getTopicTagCount' );
2894  
2895          // Return the count of tags
2896          return $count;
2897      }
2898  
2899      /**
2900       * Returns the tags in a given topic or all tags
2901       *
2902       * @since 1.0
2903       * @return integer|object The tag data when successfully executed or an IXR_Error object on failure
2904       * @param array $args Arguments passed by the XML-RPC call
2905       * @param string $args[0] The username for authentication
2906       * @param string $args[1] The password for authentication
2907       * @param integer|string $args[2] The topic id or slug (optional)
2908       *
2909       * XML-RPC request to get all tags in the topic with slug "woot-frist-topic"
2910       * <methodCall>
2911       *     <methodName>bb.getTopicTags</methodName>
2912       *     <params>
2913       *         <param><value><string>joeblow</string></value></param>
2914       *         <param><value><string>123password</string></value></param>
2915       *         <param><value><string>woot-frist-topic</string></value></param>
2916       *     </params>
2917       * </methodCall>
2918       */
2919  	function bb_getTopicTags( $args )
2920      {
2921          do_action( 'bb_xmlrpc_call', 'bb.getTopicTags' );
2922  
2923          // Escape args
2924          $this->escape( $args );
2925  
2926          // Get the login credentials
2927          $username = $args[0];
2928          $password = (string) $args[1];
2929  
2930          // Check the user is valid
2931          if ( $this->auth_readonly ) {
2932              $user = $this->authenticate( $username, $password );
2933          }
2934  
2935          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicTags' );
2936  
2937          // If an error was raised by authentication or by an action then return it
2938          if ( $this->error ) {
2939              return $this->error;
2940          }
2941  
2942          // Can be numeric id or slug
2943          $topic_id = isset( $args[2] ) ? $args[2] : false;
2944  
2945          // Check for bad data
2946          if ( $topic_id ) {
2947              if ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) {
2948                  $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
2949                  return $this->error;
2950              }
2951  
2952              // Check the requested topic exists
2953              if ( !$topic = get_topic( $topic_id ) ) {
2954                  $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
2955                  return $this->error;
2956              }
2957  
2958              // The topic id may have been a slug, so make sure it's an integer here
2959              $topic_id = (int) $topic->topic_id;
2960  
2961              // Now get the tags
2962              if ( !$tags = bb_get_topic_tags( $topic_id ) ) {
2963                  $this->error = new IXR_Error( 500, __( 'No topic tags found.' ) );
2964                  return $this->error;
2965              }
2966          } else {
2967              global $wp_taxonomy_object;
2968              $tags = $wp_taxonomy_object->get_terms( 'bb_topic_tag', array( 'get' => 'all' ) );
2969              if ( is_wp_error( $tags ) ) {
2970                  $this->error = new IXR_Error( 500, __( 'Could not retrieve all topic tags.' ) );
2971                  return $this->error;
2972              }
2973              for ( $i = 0; isset( $tags[$i] ); $i++ ) {
2974                  _bb_make_tag_compat( $tags[$i] );
2975              }
2976          }
2977  
2978          // Only include "safe" data in the array
2979          $_tags = array();
2980          foreach ( $tags as $tag ) {
2981              $_tags[] = $this->prepare_topic_tag( $tag );
2982          }
2983  
2984          do_action( 'bb_xmlrpc_call_return', 'bb.getTopicTags' );
2985  
2986          // Return the tags
2987          return $_tags;
2988      }
2989  
2990      /**
2991       * Returns the topics which are tagged with the given tag
2992       *
2993       * @since 1.0
2994       * @return integer|object The topic data when successfully executed or an IXR_Error object on failure
2995       * @param array $args Arguments passed by the XML-RPC call
2996       * @param string $args[0] The username for authentication
2997       * @param string $args[1] The password for authentication
2998       * @param string $args[2] The tag name or slug
2999       * @param integer $args[3] The number of topics to return (optional)
3000       * @param integer $args[4] The number of the page to return (optional)
3001       *
3002       * XML-RPC request to get the latest 10 topics tagged with the tag "apples"
3003       * <methodCall>
3004       *     <methodName>bb.getTopicTag</methodName>
3005       *     <params>
3006       *         <param><value><string>joeblow</string></value></param>
3007       *         <param><value><string>123password</string></value></param>
3008       *         <param><value><string>apples</string></value></param>
3009       *         <param><value><string>10</string></value></param>
3010       *     </params>
3011       * </methodCall>
3012       */
3013  	function bb_getTopicTag( $args )
3014      {
3015          do_action( 'bb_xmlrpc_call', 'bb.getTopicTag' );
3016  
3017          // Escape args
3018          $this->escape( $args );
3019  
3020          // Get the login credentials
3021          $username = $args[0];
3022          $password = (string) $args[1];
3023  
3024          // Check the user is valid
3025          if ( $this->auth_readonly ) {
3026              $user = $this->authenticate( $username, $password );
3027          }
3028  
3029          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicTag' );
3030  
3031          // If an error was raised by authentication or by an action then return it
3032          if ( $this->error ) {
3033              return $this->error;
3034          }
3035  
3036          // Can only be a string
3037          $tag_id = isset( $args[2] ) ? (string) $args[2] : false;
3038  
3039          // Check for bad data
3040          if ( !$tag_id ) {
3041              $this->error = new IXR_Error( 400, __( 'The tag id is invalid.' ) );
3042              return $this->error;
3043          }
3044  
3045          // Check the requested topic exists
3046          if ( !$tag = bb_get_tag( $tag_id ) ) {
3047              $this->error = new IXR_Error( 400, __( 'No tag found.' ) );
3048              return $this->error;
3049          }
3050  
3051          // Get the numeric tag id
3052          $tag_id = (int) $tag->tag_id;
3053  
3054          // Setup an array to store arguments to pass to get_tagged_topics() function
3055          $get_topics_args = array(
3056              'tag_id' => false,
3057              'number' => false,
3058              'page' => false
3059          );
3060  
3061          // Can only be an integer
3062          if ( isset( $args[3] ) && $number = (int) $args[3] ) {
3063              $get_topics_args['number'] = $number;
3064          }
3065  
3066          // Can only be an integer
3067          if ( isset( $args[4] ) && $page = (int) $args[4] ) {
3068              $get_topics_args['page'] = $page;
3069          }
3070  
3071          // Now get the topics
3072          if ( !$topics = get_tagged_topics( $tag_id ) ) {
3073              $this->error = new IXR_Error( 500, __( 'No topics found.' ) );
3074              return $this->error;
3075          }
3076  
3077          // Only include "safe" data in the array
3078          $_topics = array();
3079          foreach ( $topics as $topic ) {
3080              $_topics[] = $this->prepare_topic( $topic );
3081          }
3082  
3083          do_action( 'bb_xmlrpc_call_return', 'bb.getTopicTag' );
3084  
3085          // Return the topics
3086          return $_topics;
3087      }
3088  
3089      /**
3090       * Adds the specified tags to the specified topic
3091       *
3092       * @since 1.0
3093       * @return array|object The tags which were added when successfully executed or an IXR_Error object on failure
3094       * @param array $args Arguments passed by the XML-RPC call
3095       * @param string $args[0] The username for authentication
3096       * @param string $args[1] The password for authentication
3097       * @param string|integer $args[2] The topic id or slug
3098       * @param string|array $args[3] The tags to add to the topic
3099       *
3100       * XML-RPC request to add the tag "banana" to the topic with id 219
3101       * <methodCall>
3102       *     <methodName>bb.addTopicTags</methodName>
3103       *     <params>
3104       *         <param><value><string>joeblow</string></value></param>
3105       *         <param><value><string>123password</string></value></param>
3106       *         <param><value><int>219</int></value></param>
3107       *         <param><value><string>banana</string></value></param>
3108       *     </params>
3109       * </methodCall>
3110       *
3111       * XML-RPC request to add the tags "banana" and "man" to the topic with id 219
3112       * <methodCall>
3113       *     <methodName>bb.addTopicTags</methodName>
3114       *     <params>
3115       *         <param><value><string>joeblow</string></value></param>
3116       *         <param><value><string>123password</string></value></param>
3117       *         <param><value><int>219</int></value></param>
3118       *         <param><value><string>banana, man</string></value></param>
3119       *     </params>
3120       * </methodCall>
3121       *
3122       * XML-RPC request to add the tags "banana" and "man" to the topic with id 219 using an array
3123       * <methodCall>
3124       *     <methodName>bb.addTopicTags</methodName>
3125       *     <params>
3126       *         <param><value><string>joeblow</string></value></param>
3127       *         <param><value><string>123password</string></value></param>
3128       *         <param><value><int>219</int></value></param>
3129       *         <param><value><array>
3130       *             <data><value><string>banana</string></value></data>
3131       *             <data><value><string>man</string></value></data>
3132       *         </array></value></param>
3133       *     </params>
3134       * </methodCall>
3135       */
3136  	function bb_addTopicTags( $args )
3137      {
3138          do_action( 'bb_xmlrpc_call', 'bb.addTopicTags' );
3139  
3140          // Escape args
3141          $this->escape( $args );
3142  
3143          // Get the login credentials
3144          $username = $args[0];
3145          $password = (string) $args[1];
3146  
3147          // Check the user is valid
3148          $user = $this->authenticate( $username, $password, 'edit_tags', __( 'You do not have permission to edit tags.' ) );
3149  
3150          do_action( 'bb_xmlrpc_call_authenticated', 'bb.addTopicTags' );
3151  
3152          // If an error was raised by authentication or by an action then return it
3153          if ( $this->error ) {
3154              return $this->error;
3155          }
3156  
3157          // Can be numeric id or slug
3158          $topic_id = isset( $args[2] ) ? $args[2] : false;
3159  
3160          // Check for bad data
3161          if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) {
3162              $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
3163              return $this->error;
3164          }
3165  
3166          // Check the requested topic exists
3167          if ( !$topic = get_topic( $topic_id ) ) {
3168              $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
3169              return $this->error;
3170          }
3171  
3172          // The topic id may have been a slug, so make sure it's an integer here
3173          $topic_id = (int) $topic->topic_id;
3174  
3175          // Make sure they are allowed to add tags to this topic
3176          if ( !bb_current_user_can( 'add_tag_to', $topic_id ) ) {
3177              $this->error = new IXR_Error( 403, __( 'You do not have permission to add tags to this topic.' ) );
3178              return $this->error;
3179          }
3180  
3181          $tags = isset( $args[3] ) ? $args[3] : false;
3182  
3183          // Check for bad data
3184          if ( !$tags || ( !is_string( $tags ) && !is_array( $tags ) ) ) {
3185              $this->error = new IXR_Error( 400, __( 'The tag data is invalid.' ) );
3186              return $this->error;
3187          }
3188  
3189          // Add the tags
3190          if ( !$tag_ids = bb_add_topic_tags( $topic_id, $tags ) ) {
3191              $this->error = new IXR_Error( 500, __( 'The tags could not be added.' ) );
3192              return $this->error;
3193          }
3194  
3195          // Only include "safe" data in the array
3196          $_tags = array();
3197          foreach ( $tag_ids as $tag_id ) {
3198              $_tags[] = $this->prepare_topic_tag( bb_get_tag( $tag_id ) );
3199          }
3200  
3201          do_action( 'bb_xmlrpc_call_return', 'bb.addTopicTags' );
3202  
3203          // Return the tags which were added as an array
3204          return $_tags;
3205      }
3206  
3207      /**
3208       * Removes the specified tags from the specified topic
3209       *
3210       * @since 1.0
3211       * @return integer|object 1 when successfully executed or an IXR_Error object on failure
3212       * @param array $args Arguments passed by the XML-RPC call
3213       * @param string $args[0] The username for authentication
3214       * @param string $args[1] The password for authentication
3215       * @param string|integer $args[2] The topic id or slug
3216       * @param string|array $args[3] The tags to remove from the topic
3217       *
3218       * XML-RPC request to remove the tag "banana" to the topic with id 219
3219       * <methodCall>
3220       *     <methodName>bb.removeTopicTags</methodName>
3221       *     <params>
3222       *         <param><value><string>joeblow</string></value></param>
3223       *         <param><value><string>123password</string></value></param>
3224       *         <param><value><int>219</int></value></param>
3225       *         <param><value><string>banana</string></value></param>
3226       *     </params>
3227       * </methodCall>
3228       *
3229       * XML-RPC request to remove the tags "banana" and "man" to the topic with id 219
3230       * <methodCall>
3231       *     <methodName>bb.removeTopicTags</methodName>
3232       *     <params>
3233       *         <param><value><string>joeblow</string></value></param>
3234       *         <param><value><string>123password</string></value></param>
3235       *         <param><value><int>219</int></value></param>
3236       *         <param><value><string>banana, man</string></value></param>
3237       *     </params>
3238       * </methodCall>
3239       *
3240       * XML-RPC request to remove the tags "banana" and "man" to the topic with id 219 using an array
3241       * <methodCall>
3242       *     <methodName>bb.removeTopicTags</methodName>
3243       *     <params>
3244       *         <param><value><string>joeblow</string></value></param>
3245       *         <param><value><string>123password</string></value></param>
3246       *         <param><value><int>219</int></value></param>
3247       *         <param><value><array>
3248       *             <data><value><string>banana</string></value></data>
3249       *             <data><value><string>man</string></value></data>
3250       *         </array></value></param>
3251       *     </params>
3252       * </methodCall>
3253       */
3254  	function bb_removeTopicTags( $args )
3255      {
3256          do_action( 'bb_xmlrpc_call', 'bb.removeTopicTags' );
3257  
3258          // Escape args
3259          $this->escape( $args );
3260  
3261          // Get the login credentials
3262          $username = $args[0];
3263          $password = (string) $args[1];
3264  
3265          // Check the user is valid
3266          $user = $this->authenticate( $username, $password, 'edit_tags', __( 'You do not have permission to edit tags.' ) );
3267  
3268          do_action( 'bb_xmlrpc_call_authenticated', 'bb.removeTopicTags' );
3269  
3270          // If an error was raised by authentication or by an action then return it
3271          if ( $this->error ) {
3272              return $this->error;
3273          }
3274  
3275          // Can be numeric id or slug
3276          $topic_id = isset( $args[2] ) ? $args[2] : false;
3277  
3278          // Check for bad data
3279          if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) {
3280              $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) );
3281              return $this->error;
3282          }
3283  
3284          // Check the requested topic exists
3285          if ( !$topic = get_topic( $topic_id ) ) {
3286              $this->error = new IXR_Error( 400, __( 'No topic found.' ) );
3287              return $this->error;
3288          }
3289  
3290          // The topic id may have been a slug, so make sure it's an integer here
3291          $topic_id = (int) $topic->topic_id;
3292  
3293          // Make sure they are allowed to add tags to this topic
3294          if ( !bb_current_user_can( 'add_tag_to', $topic_id ) ) {
3295              $this->error = new IXR_Error( 403, __( 'You do not have permission to remove tags from this topic.' ) );
3296              return $this->error;
3297          }
3298  
3299          $tags = isset( $args[3] ) ? $args[3] : false;
3300  
3301          // Check for bad data
3302          if ( !$tags || ( !is_string( $tags ) && !is_array( $tags ) ) ) {
3303              $this->error = new IXR_Error( 400, __( 'The tag data is invalid.' ) );
3304              return $this->error;
3305          }
3306  
3307          // Add the tags
3308          if ( !bb_remove_topic_tags( $topic_id, $tags ) ) {
3309              $this->error = new IXR_Error( 500, __( 'The tags could not be removed.' ) );
3310              return $this->error;
3311          }
3312  
3313          $result = 1;
3314  
3315          do_action( 'bb_xmlrpc_call_return', 'bb.removeTopicTags' );
3316  
3317          // Return the result
3318          return $result;
3319      }
3320  
3321      /**
3322       * Renames the specified tag to a new tag name
3323       *
3324       * @since 1.0
3325       * @return array|object The tag data when successfully renamed or an IXR_Error object on failure
3326       * @param array $args Arguments passed by the XML-RPC call
3327       * @param string $args[0] The username for authentication
3328       * @param string $args[1] The password for authentication
3329       * @param string $args[2] The tag name or slug
3330       * @param string $args[3] The new tag name (slug is auto-generated)
3331       *
3332       * XML-RPC request to rename the tag "banana" to "bananas"
3333       * <methodCall>
3334       *     <methodName>bb.renameTopicTag</methodName>
3335       *     <params>
3336       *         <param><value><string>joeblow</string></value></param>
3337       *         <param><value><string>123password</string></value></param>
3338       *         <param><value><string>banana</string></value></param>
3339       *         <param><value><string>bananas</string></value></param>
3340       *     </params>
3341       * </methodCall>
3342       */
3343  	function bb_renameTopicTag( $args )
3344      {
3345          do_action( 'bb_xmlrpc_call', 'bb.renameTopicTag' );
3346  
3347          // Escape args
3348          $this->escape( $args );
3349  
3350          // Get the login credentials
3351          $username = $args[0];
3352          $password = (string) $args[1];
3353  
3354          // Check the user is valid
3355          $user = $this->authenticate( $username, $password, 'manage_tags', __( 'You do not have permission to manage tags.' ) );
3356  
3357          do_action( 'bb_xmlrpc_call_authenticated', 'bb.renameTopicTag' );
3358  
3359          // If an error was raised by authentication or by an action then return it
3360          if ( $this->error ) {
3361              return $this->error;
3362          }
3363  
3364          // Can only be a string
3365          $tag_id = isset( $args[2] ) ? (string) $args[2] : false;
3366  
3367          // Check for bad data
3368          if ( !$tag_id ) {
3369              $this->error = new IXR_Error( 400, __( 'The tag id is invalid.' ) );
3370              return $this->error;
3371          }
3372  
3373          // Check the requested tag exists
3374          if ( !$tag = bb_get_tag( $tag_id ) ) {
3375              $this->error = new IXR_Error( 400, __( 'No tag found.' ) );
3376              return $this->error;
3377          }
3378  
3379          // Get the numeric tag id
3380          $tag_id = (int) $tag->tag_id;
3381  
3382          // Can only be a string
3383          $tag_name = isset( $args[3] ) ? (string) $args[3] : false;
3384  
3385          // Check for bad data
3386          if ( !$tag_name || $tag_name == $tag->tag_name ) {
3387              $this->error = new IXR_Error( 400, __( 'The tag name is invalid.' ) );
3388              return $this->error;
3389          }
3390  
3391          // Rename the tag
3392          if ( !$new_tag = bb_rename_tag( $tag_id, $tag_name ) ) {
3393              $this->error = new IXR_Error( 500, __( 'The tag could not be renamed.' ) );
3394              return $this->error;
3395          }
3396  
3397          // Only include "safe" data in the array
3398          $new_tag = $this->prepare_topic_tag( $new_tag );
3399  
3400          do_action( 'bb_xmlrpc_call_return', 'bb.renameTopicTag' );
3401  
3402          // Return the tag
3403          return $new_tag;
3404      }
3405  
3406      /**
3407       * Merges the specified tags
3408       *
3409       * @since 1.0
3410       * @return array|object The tag data when successfully merged or an IXR_Error object on failure
3411       * @param array $args Arguments passed by the XML-RPC call
3412       * @param string $args[0] The username for authentication
3413       * @param string $args[1] The password for authentication
3414       * @param string $args[2] The old tag name or slug to be destroyed
3415       * @param string $args[3] The new tag name or slug where the old tag will be merged to
3416       *
3417       * XML-RPC request to merge the tag "banana" into the tag "apple"
3418       * <methodCall>
3419       *     <methodName>bb.mergeTopicTags</methodName>
3420       *     <params>
3421       *         <param><value><string>joeblow</string></value></param>
3422       *         <param><value><string>123password</string></value></param>
3423       *         <param><value><string>banana</string></value></param>
3424       *         <param><value><string>apple</string></value></param>
3425       *     </params>
3426       * </methodCall>
3427       */
3428  	function bb_mergeTopicTags( $args )
3429      {
3430          do_action( 'bb_xmlrpc_call', 'bb.mergeTopicTags' );
3431  
3432          // Escape args
3433          $this->escape( $args );
3434  
3435          // Get the login credentials
3436          $username = $args[0];
3437          $password = (string) $args[1];
3438  
3439          // Check the user is valid
3440          $user = $this->authenticate( $username, $password, 'manage_tags', __( 'You do not have permission to manage tags.' ) );
3441  
3442          do_action( 'bb_xmlrpc_call_authenticated', 'bb.mergeTopicTags' );
3443  
3444          // If an error was raised by authentication or by an action then return it
3445          if ( $this->error ) {
3446              return $this->error;
3447          }
3448  
3449          // Can only be strings
3450          $old_tag_id = isset( $args[2] ) ? (string) $args[2] : false;
3451          $new_tag_id = isset( $args[3] ) ? (string) $args[3] : false;
3452  
3453          // Check for bad data
3454          if ( !$old_tag_id ) {
3455              $this->error = new IXR_Error( 400, __( 'The old tag id is invalid.' ) );
3456              return $this->error;
3457          }
3458          if ( !$new_tag_id ) {
3459              $this->error = new IXR_Error( 400, __( 'The new tag id is invalid.' ) );
3460              return $this->error;
3461          }
3462  
3463          // Check the requested tags exist
3464          if ( !$old_tag = bb_get_tag( $old_tag_id ) ) {
3465              $this->error = new IXR_Error( 400, __( 'No old tag found.' ) );
3466              return $this->error;
3467          }
3468          if ( !$new_tag = bb_get_tag( $new_tag_id ) ) {
3469              $this->error = new IXR_Error( 400, __( 'No new tag found.' ) );
3470              return $this->error;
3471          }
3472  
3473          // Get the numeric tag ids
3474          $old_tag_id = (int) $old_tag->tag_id;
3475          $new_tag_id = (int) $new_tag->tag_id;
3476  
3477          // Rename the tag
3478          if ( !$result = bb_rename_tag( $old_tag_id, $new_tag_id ) ) {
3479              $this->error = new IXR_Error( 500, __( 'The tags could not be merged.' ) );
3480              return $this->error;
3481          }
3482  
3483          // Get the merged tag
3484          $new_tag = bb_get_tag( $new_tag_id );
3485  
3486          // Only include "safe" data in the array
3487          $new_tag = $this->prepare_topic_tag( $new_tag );
3488  
3489          do_action( 'bb_xmlrpc_call_return', 'bb.mergeTopicTags' );
3490  
3491          // Return the tag
3492          return $new_tag;
3493      }
3494  
3495      /**
3496       * Destroys the specified tag
3497       *
3498       * @since 1.0
3499       * @return integer|object 1 when successfully deleted or an IXR_Error object on failure
3500       * @param array $args Arguments passed by the XML-RPC call
3501       * @param string $args[0] The username for authentication
3502       * @param string $args[1] The password for authentication
3503       * @param string $args[2] The tag name or slug to be destroyed
3504       *
3505       * XML-RPC request to destroy the tag "banana"
3506       * <methodCall>
3507       *     <methodName>bb.destroyTopicTag</methodName>
3508       *     <params>
3509       *         <param><value><string>joeblow</string></value></param>
3510       *         <param><value><string>123password</string></value></param>
3511       *         <param><value><string>banana</string></value></param>
3512       *     </params>
3513       * </methodCall>
3514       */
3515  	function bb_destroyTopicTag( $args )
3516      {
3517          do_action( 'bb_xmlrpc_call', 'bb.destroyTopicTag' );
3518  
3519          // Escape args
3520          $this->escape( $args );
3521  
3522          // Get the login credentials
3523          $username = $args[0];
3524          $password = (string) $args[1];
3525  
3526          // Check the user is valid
3527          $user = $this->authenticate( $username, $password, 'manage_tags', __( 'You do not have permission to manage tags.' ) );
3528  
3529          do_action( 'bb_xmlrpc_call_authenticated', 'bb.destroyTopicTag' );
3530  
3531          // If an error was raised by authentication or by an action then return it
3532          if ( $this->error ) {
3533              return $this->error;
3534          }
3535  
3536          // Can only be a string
3537          $tag_id = isset( $args[2] ) ? (string) $args[2] : false;
3538  
3539          // Check for bad data
3540          if ( !$tag_id ) {
3541              $this->error = new IXR_Error( 400, __( 'The tag id is invalid.' ) );
3542              return $this->error;
3543          }
3544  
3545          // Check the requested tag exists
3546          if ( !$tag = bb_get_tag( $tag_id ) ) {
3547              $this->error = new IXR_Error( 400, __( 'No tag found.' ) );
3548              return $this->error;
3549          }
3550  
3551          // Get the numeric tag id
3552          $tag_id = (int) $tag->tag_id;
3553  
3554          // Destroy the tag
3555          if ( !$result = bb_destroy_tag( $tag_id ) ) {
3556              $this->error = new IXR_Error( 500, __( 'The tag could not be destroyed.' ) );
3557              return $this->error;
3558          }
3559  
3560          $result = 1;
3561  
3562          do_action( 'bb_xmlrpc_call_return', 'bb.destroyTopicTag' );
3563  
3564          // Return the tag
3565          return $result;
3566      }
3567  
3568  
3569  
3570      /**
3571       * bbPress publishing API - Options XML-RPC methods
3572       */
3573  
3574      /**
3575       * Initialises site options which can be manipulated using XML-RPC
3576       *
3577       * @since 1.0
3578       * @return void
3579       */
3580  	function initialise_site_option_info()
3581      {
3582          $this->site_options = array(
3583              // Read only options
3584              'software_name'        => array(
3585                  'desc'            => __( 'Software Name' ),
3586                  'readonly'        => true,
3587                  'value'            => 'bbPress'
3588              ),
3589              'software_version'    => array(
3590                  'desc'            => __( 'Software Version' ),
3591                  'readonly'        => true,
3592                  'option'        => 'version'
3593              ),
3594              'site_url'            => array(
3595                  'desc'            => __( 'Site URL' ),
3596                  'readonly'        => true,
3597                  'option'        => 'uri'
3598              ),
3599  
3600              // Updatable options
3601              'site_name'        => array(
3602                  'desc'            => __( 'Site Name' ),
3603                  'readonly'        => false,
3604                  'option'        => 'name'
3605              ),
3606              'site_description'    => array(
3607                  'desc'            => __( 'Site Description' ),
3608                  'readonly'        => false,
3609                  'option'        => 'description'
3610              ),
3611              'time_zone'            => array(
3612                  'desc'            => __( 'Time Zone' ),
3613                  'readonly'        => false,
3614                  'option'        => 'gmt_offset'
3615              ),
3616              'datetime_format'    => array(
3617                  'desc'            => __( 'Date/Time Format' ),
3618                  'readonly'        => false,
3619                  'option'        => 'datetime_format'
3620              ),
3621              'date_format'        => array(
3622                  'desc'            => __( 'Date Format' ),
3623                  'readonly'        => false,
3624                  'option'        => 'date_format'
3625              )
3626          );
3627  
3628          $this->site_options = apply_filters( 'xmlrpc_site_options', $this->site_options );
3629      }
3630  
3631      /**
3632       * Compiles site options into an array suitable to be passed back through the XML-RPC server
3633       *
3634       * @since 1.0
3635       * @return array The site options in an array
3636       * @param array $options An array of options to fetch and return
3637       */
3638  	function _getOptions( $options )
3639      {
3640          $data = array();
3641          foreach ( $options as $option ) {
3642              if ( array_key_exists( $option, $this->site_options ) ) {
3643                  $data[$option] = $this->site_options[$option];
3644  
3645                  // Is the value static or dynamic?
3646                  if ( isset( $data[$option]['option'] ) ) {
3647                      $data[$option]['value'] = bb_get_option( $data[$option]['option'] );
3648                      unset( $data[$option]['option'] );
3649                  }
3650              }
3651          }
3652  
3653          return $data;
3654      }
3655  
3656      /**
3657       * Gets the specified site options
3658       *
3659       * @since 1.0
3660       * @return array|object An array containing the specified options when successfully executed or an IXR_Error object on failure
3661       * @param array $args Arguments passed by the XML-RPC call
3662       * @param string $args[0] The username for authentication
3663       * @param string $args[1] The password for authentication
3664       * @param array $args[2] The options to be retrieved, when omitted the method returns all options (optional)
3665       *
3666       * XML-RPC request to get all site options
3667       * <methodCall>
3668       *     <methodName>bb.getOptions</methodName>
3669       *     <params>
3670       *         <param><value><string>joeblow</string></value></param>
3671       *         <param><value><string>123password</string></value></param>
3672       *     </params>
3673       * </methodCall>
3674       *
3675       * XML-RPC request to get the site name and site description
3676       * <methodCall>
3677       *     <methodName>bb.getOptions</methodName>
3678       *     <params>
3679       *         <param><value><string>joeblow</string></value></param>
3680       *         <param><value><string>123password</string></value></param>
3681       *         <param><value><array>
3682       *             <data><value><string>site_name</string></value></data>
3683       *             <data><value><string>site_description</string></value></data>
3684       *         </array></value></param>
3685       *     </params>
3686       * </methodCall>
3687       */
3688  	function bb_getOptions( $args )
3689      {
3690          do_action( 'bb_xmlrpc_call', 'bb.getOptions' );
3691  
3692          // Escape args
3693          $this->escape( $args );
3694  
3695          // Get the login credentials
3696          $username = $args[0];
3697          $password = (string) $args[1];
3698  
3699          // Check the user is valid
3700          if ( $this->auth_readonly ) {
3701              $user = $this->authenticate( $username, $password );
3702          }
3703  
3704          do_action( 'bb_xmlrpc_call_authenticated', 'bb.getOptions' );
3705  
3706          // If an error was raised by authentication or by an action then return it
3707          if ( $this->error ) {
3708              return $this->error;
3709          }
3710  
3711          // If there are parameters supplied then make sure they are in an array
3712          $options = isset( $args[2] ) ? (array) $args[2] : false;
3713  
3714          // If no specific options where asked for, return all of them
3715          if ( !$options || !count( $options ) ) {
3716              $options = array_keys( $this->site_options );
3717          }
3718  
3719          do_action( 'bb_xmlrpc_call_return', 'bb.getOptions' );
3720  
3721          return $this->_getOptions( $options );
3722      }
3723  
3724      /**
3725       * Sets the specified site options to the specified values
3726       *
3727       * @since 1.0
3728       * @return array|object An array containing the specified options when successfully executed or an IXR_Error object on failure
3729       * @param array $args Arguments passed by the XML-RPC call
3730       * @param string $args[0] The username for authentication
3731       * @param string $args[1] The password for authentication
3732       * @param array $args[2] The options to be updated along with the new value of the option
3733       *
3734       * XML-RPC request to set the site name and site description
3735       * <methodCall>
3736       *     <methodName>bb.setOptions</methodName>
3737       *     <params>
3738       *         <param><value><string>joeblow</string></value></param>
3739       *         <param><value><string>123password</string></value></param>
3740       *         <param><value><struct>
3741       *             <member>
3742       *                 <name>site_name</name>
3743       *                 <value><string>Awesome forums</string></value>
3744       *             </member>
3745       *             <member>
3746       *                 <name>site_description</name>
3747       *                 <value><string>My totally awesome forums will kick your butt</string></value>
3748       *             </member>
3749       *         </struct></value></param>
3750       *     </params>
3751       * </methodCall>
3752       */
3753  	function bb_setOptions( $args )
3754      {
3755          do_action( 'bb_xmlrpc_call', 'bb.setOptions' );
3756  
3757          // Escape args
3758          $this->escape( $args );
3759  
3760          // Get the login credentials
3761          $username = $args[0];
3762          $password = (string) $args[1];
3763  
3764          // Check the user is valid
3765          $user = $this->authenticate( $username, $password, 'manage_options', __( 'You are not allowed to manage options.' ) );
3766  
3767          do_action( 'bb_xmlrpc_call_authenticated', 'bb.setOptions' );
3768  
3769          // If an error was raised by authentication or by an action then return it
3770          if ( $this->error ) {
3771              return $this->error;
3772          }
3773  
3774          // Make sure there is something for us to do
3775          if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) {
3776              $this->error = new IXR_Error( 400, __( 'The options data is invalid.' ) );
3777              return $this->error;
3778          }
3779  
3780          $options = (array) $args[2];
3781  
3782          // Update the requested options
3783          foreach( $options as $o_name => $o_value ) {
3784              $option_names[] = $o_name;
3785  
3786              // If there is no value set skip it
3787              if ( empty( $o_value ) ) {
3788                  continue;
3789              }
3790  
3791              // If the option doesn't exist skip it
3792              if ( !array_key_exists( $o_name, $this->site_options ) ) {
3793                  continue;
3794              }
3795  
3796              // If the option is readonly skip it
3797              if ( $this->site_options[$o_name]['readonly'] == true ) {
3798                  continue;
3799              }
3800  
3801              // Everything is good, update the option
3802              bb_update_option( $this->site_options[$o_name]['option'], $o_value );
3803          }
3804  
3805          $_options = $this->_getOptions( $option_names );
3806  
3807          do_action( 'bb_xmlrpc_call_return', 'bb.setOptions' );
3808  
3809          // Now return the updated values
3810          return $_options;
3811      }
3812  
3813  
3814  
3815      /**
3816       * Pingback XML-RPC methods
3817       */
3818  
3819      /**
3820       * Processes pingback requests
3821       *
3822       * @since 1.0
3823       * @link http://www.hixie.ch/specs/pingback/pingback
3824       * @return string|object A message of success or an IXR_Error object on failure
3825       * @param array $args Arguments passed by the XML-RPC call
3826       * @param string $args[0] The full URI of the post where the pingback is being sent from
3827       * @param string $args[1] The full URI of the post where the pingback is being sent to
3828       *
3829       * XML-RPC request to register a pingback
3830       * <methodCall>
3831       *     <methodName>pingback.ping</methodName>
3832       *     <params>
3833       *         <param><value><string>http://example.org/2008/09/post-containing-a-link/</string></value></param>
3834       *         <param><value><string>http://example.com/2008/08/post-being-linked-to/</string></value></param>
3835       *     </params>
3836       * </methodCall>
3837       */
3838  	function pingback_ping( $args )
3839      {
3840          do_action( 'bb_xmlrpc_call', 'pingback.ping' );
3841  
3842          $this->escape( $args );
3843  
3844          // No particular need to sanitise
3845          $link_from = (string) $args[0];
3846          $link_to   = (string) $args[1];
3847  
3848          // Tidy up ampersands in the URLs
3849          $link_from = str_replace( '&amp;', '&', $link_from );
3850          $link_to   = str_replace( '&amp;', '&', $link_to );
3851          $link_to   = str_replace( '&', '&amp;', $link_to );
3852  
3853          // Check if the topic linked to is in our site - a little more strict than WordPress, doesn't pull out the www if added
3854          if ( !bb_match_domains( $link_to, bb_get_uri() ) ) {
3855              // These are not the droids you are looking for
3856              $this->error = new IXR_Error( 0, __( 'This is not the site you are trying to pingback.' ) );
3857              return $this->error;
3858          }
3859  
3860          // Get the topic
3861          if ( $topic_to = bb_get_topic_from_uri( $link_to ) ) {
3862              // Topics shouldn't ping themselves
3863              if ( $topic_from = bb_get_topic_from_uri( $link_from ) ) {
3864                  if ( $topic_from->topic_id === $topic_to->topic_id ) {
3865                      $this->error = new IXR_Error( 0, __( 'The source URL and the target URL cannot both point to the same resource.' ) );
3866                      return $this->error;
3867                  }
3868              }
3869          } else {
3870              $this->error = new IXR_Error ( 33, __( 'The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.' ) );
3871              return $this->error;
3872          }
3873  
3874          // Let's check that the remote site didn't already pingback this entry
3875          $query = new BB_Query( 'post', array( 'topic_id' => $topic_to->topic_id, 'append_meta' => true ), 'get_thread' );
3876          $posts_to = $query->results;
3877          unset( $query );
3878  
3879          // Make sure we have some posts in the topic, this error should never happen really
3880          if ( !$posts_to || !is_array( $posts_to ) || !count( $posts_to ) ) {
3881              $this->error = new IXR_Error( 0, __( 'The specified target topic does not contain any posts.' ) );
3882              return $this->error;
3883          }
3884  
3885          // Check if we already have a pingback from this URL
3886          foreach ( $posts_to as $post ) {
3887              if ( isset( $post->pingback_uri ) && trim( $post->pingback_uri ) === trim( $link_from ) ) {
3888                  $this->error = new IXR_Error( 48, __( 'The pingback has already been registered.' ) );
3889                  return $this->error;
3890              }
3891          }
3892          unset( $posts_to, $post );
3893  
3894          // Give time for the server sending the pingback to finish publishing it's post
3895          sleep(1);
3896  
3897          // Let's check the remote site for valid URL and content
3898          $link_from_source = wp_remote_fopen( $link_from );
3899          if ( !$link_from_source ) {
3900              $this->error = new IXR_Error( 16, __( 'The source URL does not exist.' ) );
3901              return $this->error;
3902          }
3903  
3904          // Allow plugins to filter here
3905          $link_from_source = apply_filters( 'bb_pre_remote_source', $link_from_source, $link_to );
3906  
3907          // Work around bug in strip_tags()
3908          $link_from_source = str_replace( '<!DOC', '<DOC', $link_from_source );
3909  
3910          // Normalize spaces
3911          $link_from_source = preg_replace( '/[\s\r\n\t]+/', ' ', $link_from_source );
3912  
3913          // Turn certain elements to double line returns
3914          $link_from_source = preg_replace( "/ <(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $link_from_source );
3915  
3916          // Find the title of the page
3917          preg_match( '|<title>([^<]*?)</title>|is', $link_from_source, $link_from_title );
3918          $link_from_title = $link_from_title[1];
3919          if ( empty( $link_from_title ) ) {
3920              $this->error = new IXR_Error( 32, __( 'We cannot find a title on that page.' ) );
3921              return $this->error;
3922          }
3923  
3924          // Strip out all tags except anchors
3925          $link_from_source = strip_tags( $link_from_source, '<a>' ); // just keep the tag we need
3926  
3927          // Split the source into paragraphs
3928          $link_from_paragraphs = explode( "\n\n", $link_from_source );
3929  
3930          // Prepare the link to search for in preg_match() once here
3931          $preg_target = preg_quote( $link_to );
3932  
3933          // Loop through the paragraphs looking for the context for the url
3934          foreach ( $link_from_paragraphs as $link_from_paragraph ) {
3935              // The url exists
3936              if ( strpos( $link_from_paragraph, $link_to ) !== false ) {
3937                  // But is it in an anchor tag
3938                  preg_match(
3939                      "|<a[^>]+?" . $preg_target . "[^>]*>([^>]+?)</a>|",
3940                      $link_from_paragraph,
3941                      $context
3942                  );
3943                  // If the URL isn't in an anchor tag, keep looking
3944                  if ( empty( $context ) ) {
3945                      continue;
3946                  }
3947  
3948                  // We're going to use this fake tag to mark the context in a bit
3949                  // the marker is needed in case the link text appears more than once in the paragraph
3950                  $excerpt = preg_replace( '|\</?wpcontext\>|', '', $link_from_paragraph );
3951  
3952                  // Prevent really long link text
3953                  if ( strlen( $context[1] ) > 100 ) {
3954                      $context[1] = substr( $context[1], 0, 100 ) . '...';
3955                  }
3956  
3957                  // Set up the marker around the context
3958                  $marker = '<wpcontext>' . $context[1] . '</wpcontext>';
3959                  // Swap out the link for our marker
3960                  $excerpt = str_replace( $context[0], $marker, $excerpt );
3961                  // Strip all tags except for our context marker
3962                  $excerpt = trim( strip_tags( $excerpt, '<wpcontext>' ) );
3963                  // Make the marker safe for use in regexp
3964                  $preg_marker = preg_quote( $marker );
3965                  // Reduce the excerpt to only include 100 characters on either side of the link
3966                  $excerpt = preg_replace( "|.*?\s(.{0,100}" . $preg_marker . "{0,100})\s.*|s", '$1', $excerpt );
3967                  // Strip tags again, to remove the marker wrapper
3968                  $excerpt = strip_tags( $excerpt );
3969                  break;
3970              }
3971          }
3972  
3973           // Make sure the link to the target was found in the excerpt
3974          if ( empty( $context ) ) {
3975              $this->error = new IXR_Error( 17, __( 'The source URL does not contain a link to the target URL, and so cannot be used as a source.' ) );
3976              return $this->error;
3977          }
3978  
3979          // Add whacky prefix and suffix to the excerpt and sanitize
3980          $excerpt = '[...] ' . esc_html( $excerpt ) . ' [...]';
3981          $this->escape( $excerpt );
3982  
3983          // Build an array of post data to insert then insert a new post
3984          $postdata = array(
3985              'topic_id' => $topic_to->topic_id,
3986              'post_text' => $excerpt,
3987              'poster_id' => 0,
3988          );
3989          if ( !$post_ID = bb_insert_post( $postdata ) ) {
3990              $this->error = new IXR_Error( 0, __( 'The pingback could not be added.' ) );
3991              return $this->error;
3992          }
3993  
3994          // Add meta to let us know where the pingback came from
3995          $link_from = str_replace( '&', '&amp;', $link_from );
3996          $this->escape( $link_from );
3997          bb_update_postmeta( $post_ID, 'pingback_uri', $link_from );
3998  
3999          // Add the title to meta
4000          $this->escape( $link_from_title );
4001          bb_update_postmeta( $post_ID, 'pingback_title', $link_from_title );
4002  
4003          // Action for plugins and what not
4004          do_action( 'bb_pingback_post', $post_ID );
4005  
4006          // Return success message, complete with emoticon
4007          return sprintf( __( 'Pingback from %1$s to %2$s registered. Keep the web talking! :-)' ), $link_from, $link_to );
4008      }
4009  
4010  
4011  
4012      /**
4013       * Returns an array of URLs that pingbacked the given URL
4014       *
4015       * @since 1.0
4016       * @link http://www.aquarionics.com/misc/archives/blogite/0198.html
4017       * @return array The array of URLs that pingbacked the given topic
4018       * @param array $args Arguments passed by the XML-RPC call
4019       * @param string $args[0] The full URI of the post where the pingback is being sent from
4020       * @param string $args[1] The full URI of the post where the pingback is being sent to
4021       *
4022       * XML-RPC request to get all pingbacks on a topic
4023       * <methodCall>
4024       *     <methodName>pingback.ping</methodName>
4025       *     <params>
4026       *         <param><value><string>http://example.com/2008/08/post-tobe-queried/</string></value></param>
4027       *     </params>
4028       * </methodCall>
4029       */
4030  	function pingback_extensions_getPingbacks( $args )
4031      {
4032          do_action( 'bb_xmlrpc_call', 'pingback.extensions.getPingbacks' );
4033  
4034          $this->escape( $args );
4035  
4036          // Don't accept arrays of arguments
4037          if ( is_array( $args ) ) {
4038              $this->error = new IXR_Error( 404, __( 'The requested method only accepts one parameter.' ) );
4039              return $this->error;
4040          } else {
4041              $url = (string) $args;
4042          }
4043  
4044          // Tidy up ampersands in the URI
4045          $url = str_replace( '&amp;', '&', $url );
4046          $url = str_replace( '&', '&amp;', $url );
4047  
4048          // Check if the URI is in our site
4049          if ( !bb_match_domains( $url, bb_get_uri() ) ) {
4050              // These are not the droids you are looking for
4051              $this->error = new IXR_Error( 0, __( 'The specified target URL is not on this domain.' ) );
4052              return $this->error;
4053          }
4054  
4055          // Make sure the specified URI is in fact associated with a topic
4056          if ( !$topic = bb_get_topic_from_uri( $url ) ) {
4057              $this->error = new IXR_Error( 33, __( 'The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.' ) );
4058              return $this->error;
4059          }
4060  
4061          // Grab the posts from the topic
4062          $query = new BB_Query( 'post', array( 'topic_id' => $topic_to->topic_id, 'append_meta' => true ), 'get_thread' );
4063          $posts_to = $query->results;
4064          unset( $query );
4065  
4066          // Check for pingbacks in the post meta data
4067          $pingbacks = array();
4068          foreach ( $posts_to as $post ) {
4069              if ( isset( $post->pingback_uri ) ) {
4070                  $pingbacks[] = $post->pingback_uri;
4071              }
4072          }
4073          unset( $post );
4074  
4075          // This will return an empty array on failure
4076          return $pingbacks;
4077      }
4078  }
4079  
4080  
4081  
4082  /**
4083   * Initialises the XML-RPC server
4084   *
4085   * @since 1.0
4086   * @var object The instance of the XML-RPC server class
4087   */
4088  $bb_xmlrpc_server = new BB_XMLRPC_Server();


Generated: Thu Dec 7 01:01:35 2017 Cross-referenced by PHPXref 0.7.1