'this:pingback_ping',
# MetaWeblog
'metaWeblog.getRecentPosts' => 'this:metaWeblog_getRecentPosts',
'metaWeblog.getCategories' => 'this:metaWeblog_getCategories',
'metaWeblog.newMediaObject' => 'this:metaWeblog_newMediaObject',
'metaWeblog.newPost' => 'this:metaWeblog_newPost',
'metaWeblog.getPost' => 'this:metaWeblog_getPost',
'metaWeblog.editPost' => 'this:metaWeblog_editPost',
# Blogger
'blogger.deletePost' => 'this:blogger_deletePost',
'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
'blogger.getUserInfo' => 'this:blogger_getUserInfo',
# MovableType
'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
'mt.getCategoryList' => 'this:mt_getCategoryList',
'mt.getPostCategories' => 'this:mt_getPostCategories',
'mt.setPostCategories' => 'this:mt_setPostCategories',
'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
'mt.supportedMethods' => 'this:listMethods',
# Chyrp
"chyrp.getRecentPosts" => "this:chyrp_getRecentPosts",
"chyrp.newPost" => "this:chyrp_newPost",
"chyrp.getPost" => "this:chyrp_getPost",
"chyrp.editPost" => "this:chyrp_editPost");
Trigger::current()->filter($methods, "xmlrpc_methods");
$this->IXR_Server($methods);
}
#
# Function: pingback_ping
# Receive and register pingbacks. Calls the @pingback@ trigger.
#
public function pingback_ping($args) {
$config = Config::current();
$linked_from = str_replace('&', '&', $args[0]);
$linked_to = str_replace('&', '&', $args[1]);
$cleaned_url = str_replace(array("http://www.", "http://"), "", $config->url);
if ($linked_to == $linked_from)
return new IXR_ERROR(0, __("The from and to URLs cannot be the same."));
if (!substr_count($linked_to, $cleaned_url))
return new IXR_Error(0, __("There doesn't seem to be a valid link in your request."));
if (preg_match("/url=([^]+)/", $linked_to, $url))
$post = new Post(array("url" => $url[1]));
else
$post = MainController::current()->post_from_url(null,
str_replace(rtrim($config->url, "/"), "/", $linked_to),
true);
if (!$post)
return new IXR_Error(33, __("I can't find a post from that URL."));
# Wait for the "from" server to publish
sleep(1);
$from = parse_url($linked_from);
if (empty($from["host"]))
return false;
if (empty($from["scheme"]) or $from["scheme"] != "http")
$linked_from = "http://".$linked_from;
# Grab the page that linked here.
$content = get_remote($linked_from);
# Get the title of the page.
preg_match("/
([^<]+)<\/title>/i", $content, $title);
$title = $title[1];
if (empty($title))
return new IXR_Error(32, __("There isn't a title on that page."));
$content = strip_tags($content, "");
$url = preg_quote($linked_to, "/");
if (!preg_match("/]*{$url}[^>]*>([^>]*)<\/a>/", $content, $context)) {
$url = str_replace("&", "&", preg_quote($linked_to, "/"));
if (!preg_match("/]*{$url}[^>]*>([^>]*)<\/a>/", $content, $context)) {
$url = str_replace("&", "&", preg_quote($linked_to, "/"));
if (!preg_match("/]*{$url}[^>]*>([^>]*)<\/a>/", $content, $context))
return false;
}
}
$context[1] = truncate($context[1], 100, "...", true);
$excerpt = strip_tags(str_replace($context[0], $context[1], $content));
$match = preg_quote($context[1], "/");
$excerpt = preg_replace("/.*?\s(.{0,100}{$match}.{0,100})\s.*/s", "\\1", $excerpt);
$excerpt = "[...] ".trim(normalize($excerpt))." [...]";
Trigger::current()->call("pingback", $post, $linked_to, $linked_from, $title, $excerpt);
return _f("Pingback from %s to %s registered!", array($linked_from, $linked_to));
}
#
# Function: metaWeblog_getRecentPosts
# Returns a list of the most recent posts.
#
public function metaWeblog_getRecentPosts($args) {
$this->auth($args[1], $args[2]);
$config = Config::current();
$trigger = Trigger::current();
$result = array();
foreach ($this->getRecentPosts($args[3]) as $post) {
$struct = array(
'postid' => $post->id,
'userid' => $post->user_id,
'title' => $post->title,
'dateCreated' => new IXR_Date(when('Ymd\TH:i:s', $post->created_at)),
'description' => $post->body,
'link' => $post->url(),
'permaLink' => $post->url(),
'mt_basename' => $post->url,
'mt_allow_pings' => (int) $config->enable_trackbacking);
$result[] = $trigger->filter($struct, 'metaWeblog_getPost', $post);
}
return $result;
}
#
# Function: metaWeblog_getCategories
# Returns a list of all categories to which the post is assigned.
#
public function metaWeblog_getCategories($args) {
$this->auth($args[1], $args[2]);
$categories = array();
return Trigger::current()->filter($categories, 'metaWeblog_getCategories');
}
#
# Function: metaWeblog_newMediaObject
# Uploads a file to the server.
#
public function metaWeblog_newMediaObject($args) {
$this->auth($args[1], $args[2]);
$config = Config::current();
$file = unique_filename(trim($args[3]['name'], ' /'));
$path = MAIN_DIR.$config->uploads_path.$file;
if (file_put_contents($path, $args[3]['bits']) === false)
return new IXR_Error(500, __("Failed to write file."));
$url = $config->chyrp_url.$config->uploads_path.str_replace('+', '%20', urlencode($file));
Trigger::current()->filter($url, 'metaWeblog_newMediaObject', $path);
return array('url' => $url);
}
#
# Function: metaWeblog_getPost
# Retrieves a specified post.
#
public function metaWeblog_getPost($args) {
$this->auth($args[1], $args[2]);
$post = new Post($args[0], array('filter' => false));
$struct = array(
'postid' => $post->id,
'userid' => $post->user_id,
'title' => $post->title,
'dateCreated' => new IXR_Date(when('Ymd\TH:i:s', $post->created_at)),
'description' => $post->body,
'link' => $post->url(),
'permaLink' => $post->url(),
'mt_basename' => $post->url,
'mt_allow_pings' => (int) Config::current()->enable_trackbacking);
Trigger::current()->filter($struct, 'metaWeblog_getPost', $post);
return array($struct);
}
#
# Function: metaWeblog_newPost
# Creates a new post.
#
public function metaWeblog_newPost($args) {
$this->auth($args[1], $args[2], 'add');
global $user;
# Support for extended body
$body = $args[3]['description'];
if (!empty($args[3]['mt_text_more']))
$body .= ''.$args[3]['mt_text_more'];
# Add excerpt to body so it isn't lost
if (!empty($args[3]['mt_excerpt']))
$body = $args[3]['mt_excerpt']."\n\n".$body;
if (trim($body) === '')
return new IXR_Error(500, __("Body can't be blank."));
$clean = sanitize(oneof(@$args[3]['mt_basename'], $args[3]['title']));
$url = Post::check_url($clean);
$_POST['user_id'] = $user->id;
$_POST['feather'] = XML_RPC_FEATHER;
$_POST['created_at'] = oneof($this->convertFromDateCreated($args[3]), datetime());
if ($user->group->can('add_post'))
$_POST['status'] = ($args[4]) ? 'public' : 'draft';
else
$_POST['status'] = 'draft';
$trigger = Trigger::current();
$trigger->call('metaWeblog_newPost_preQuery', $args[3]);
$post = Post::add(
array(
'title' => $args[3]['title'],
'body' => $body),
$clean,
$url);
if ($post->no_results)
return new IXR_Error(500, __("Post not found."));
$trigger->call('metaWeblog_newPost', $args[3], $post);
# Send any and all pingbacks to URLs in the body
if (Config::current()->send_pingbacks)
send_pingbacks($args[3]['description'], $post);
return $post->id;
}
#
# Function: metaWeblog_editPost
# Updates a specified post.
#
public function metaWeblog_editPost($args) {
$this->auth($args[1], $args[2], 'edit');
global $user;
if (!Post::exists($args[0]))
return new IXR_Error(500, __("Post not found."));
# Support for extended body
$body = $args[3]['description'];
if (!empty($args[3]['mt_text_more']))
$body .= ''.$args[3]['mt_text_more'];
# Add excerpt to body so it isn't lost
if (!empty($args[3]['mt_excerpt']))
$body = $args[3]['mt_excerpt']."\n\n".$body;
if (trim($body) === '')
return new IXR_Error(500, __("Body can't be blank."));
$post = new Post($args[0], array('filter' => false));
# More specific permission check
if (!$post->editable($user))
return new IXR_Error(500, __("You don't have permission to edit this post."));
# Enforce post status when necessary
if (!$user->group->can('edit_own_post', 'edit_post'))
$status = 'draft';
else if ($post->status !== 'public' and $post->status !== 'draft')
$status = $post->status;
else
$status = ($args[4]) ? 'public' : 'draft';
$trigger = Trigger::current();
$trigger->call('metaWeblog_editPost_preQuery', $args[3], $post);
$post->update(
array('title' => $args[3]['title'], 'body' => $body ),
null,
null,
$status,
sanitize(oneof(@$args[3]['mt_basename'], $args[3]['title'])),
oneof($this->convertFromDateCreated($args[3]), $post->created_at));
$trigger->call('metaWeblog_editPost', $args[3], $post);
return true;
}
#
# Function: blogger_deletePost
# Deletes a specified post.
#
public function blogger_deletePost($args) {
$this->auth($args[2], $args[3], 'delete');
global $user;
$post = new Post($args[1], array('filter' => false));
if ($post->no_results)
return new IXR_Error(500, __("Post not found."));
else if (!$post->deletable($user))
return new IXR_Error(500, __("You don't have permission to delete this post."));
Post::delete($args[1]);
return true;
}
#
# Function: blogger_getUsersBlogs
# Returns information about the Chyrp installation.
#
public function blogger_getUsersBlogs($args) {
$this->auth($args[1], $args[2]);
$config = Config::current();
return array(array(
'url' => $config->url,
'blogName' => $config->name,
'blogid' => 1));
}
#
# Function: blogger_getUserInfo
# Retrieves a specified user.
#
public function blogger_getUserInfo($args) {
$this->auth($args[1], $args[2]);
global $user;
return array(array(
'userid' => $user->id,
'nickname' => $user->full_name,
'firstname' => '',
'lastname' => '',
'email' => $user->email,
'url' => $user->website));
}
#
# Function: mt_getRecentPostTitles
# Returns a bandwidth-friendly list of the most recent posts.
#
public function mt_getRecentPostTitles($args) {
$this->auth($args[1], $args[2]);
$result = array();
foreach ($this->getRecentPosts($args[3]) as $post) {
$result[] = array(
'postid' => $post->id,
'userid' => $post->user_id,
'title' => $post->title,
'dateCreated' => new IXR_Date(when('Ymd\TH:i:s', $post->created_at)));
}
return $result;
}
#
# Function: mt_getCategoryList
# Returns a list of categories.
#
public function mt_getCategoryList($args) {
$this->auth($args[1], $args[2]);
$categories = array();
return Trigger::current()->filter(
$categories,
'mt_getCategoryList');
}
#
# Function: mt_getPostCategories
# Returns a list of all categories to which the post is assigned.
#
public function mt_getPostCategories($args) {
$this->auth($args[1], $args[2]);
if (!Post::exists($args[0]))
return new IXR_Error(500, __("Post not found."));
$categories = array();
return Trigger::current()->filter(
$categories,
'mt_getPostCategories',
new Post($args[0], array('filter' => false)));
}
#
# Function: mt_setPostCategories
# Sets the categories for a post.
#
public function mt_setPostCategories($args) {
$this->auth($args[1], $args[2], 'edit');
global $user;
$post = new Post($args[0], array('filter' => false));
if ($post->no_results)
return new IXR_Error(500, __("Post not found."));
else if (!$post->deletable($user))
return new IXR_Error(500, __("You don't have permission to edit this post."));
Trigger::current()->call('mt_setPostCategories', $args[3], $post);
return true;
}
#
# Function: mt_supportedTextFilters
# Returns an empty array, as this is not applicable for Chyrp.
#
public function mt_supportedTextFilters() {
return array();
}
#
# Function: getRecentPosts
# Returns an array of the most recent posts.
#
private function getRecentPosts($limit) {
global $user;
if (!in_array(XML_RPC_FEATHER, Config::current()->enabled_feathers))
throw new Exception(_f("The %s feather is not enabled.", array(XML_RPC_FEATHER)));
$where = array('feather' => XML_RPC_FEATHER);
if ($user->group->can('view_own_draft', 'view_draft'))
$where['status'] = array('public', 'draft');
else
$where['status'] = 'public';
if (!$user->group->can('view_draft', 'edit_draft', 'edit_post', 'delete_draft', 'delete_post'))
$where['user_id'] = $user->id;
return Post::find(
array(
'where' => $where,
'order' => 'created_at DESC, id DESC',
'limit' => $limit),
array('filter' => false));
}
#
# Function: convertFromDateCreated
# Converts an IXR_Date (in $args['dateCreated']) to SQL date format.
#
private function convertFromDateCreated($args) {
if (array_key_exists('dateCreated', $args))
return when('Y-m-d H:i:s', $args['dateCreated']->getIso());
else
return null;
}
#
# Function: auth
# Authenticates a given login and password, and checks for appropriate permission
#
private function auth($login, $password, $do = 'add') {
if (!Config::current()->enable_xmlrpc)
throw new Exception(__("XML-RPC support is disabled for this site."));
global $user;
if (!User::authenticate($login, $password))
throw new Exception(__("Login incorrect."));
else
$user = new User(
null,
array(
'where' => array(
'login' => $login
)
)
);
if (!$user->group->can("{$do}_own_post", "{$do}_post", "{$do}_draft", "{$do}_own_draft"))
throw new Exception(_f("You don't have permission to %s posts/drafts.", array($do)));
}
#
# Function: error_handler
#
public static function error_handler($errno, $errstr, $errfile, $errline) {
if (error_reporting() === 0 or $errno == E_STRICT) return;
throw new Exception(sprintf("%s in %s on line %s", $errstr, $errfile, $errline));
}
#
# Function: exception_handler
#
public static function exception_handler($exception) {
$ixr_error = new IXR_Error(500, $exception->getMessage());
echo $ixr_error->getXml();
}
}
$server = new XMLRPC();
?>