<?php
/**
 * XML-RPC : Blogger API
 *
 * @see http://manual.b2evolution.net/Blogger_API
 * @see http://www.blogger.com/developers/api/1_docs/
 * @see http://www.sixapart.com/developers/xmlrpc/blogger_api/
 *
 * b2evolution - {@link http://b2evolution.net/}
 * Released under GNU GPL License - {@link http://b2evolution.net/about/license.html}
 * @copyright (c)2003-2008 by Francois PLANQUE - {@link http://fplanque.net/}
 *
 * @package xmlsrv
 *
 * @version $Id: _blogger.api.php,v 1.2 2008/01/18 15:53:42 fplanque Exp $
 */
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );


$bloggernewpost_doc = 'Adds a post, blogger-api like';
$bloggernewpost_sig = array(array($xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcBoolean));
/**
 * blogger.newPost makes a new post to a designated blog.
 *
 * Optionally, will publish the blog after making the post. (In b2evo, this means the
 * new post will be in 'published' state).
 * On success, it returns the unique ID of the new post (usually a seven-digit number
 * at this time).
 * On error, it will return some error message.
 *
 * @see http://www.blogger.com/developers/api/1_docs/xmlrpc_newPost.html
 * @see http://www.sixapart.com/developers/xmlrpc/blogger_api/bloggernewpost.html
 *
 * @param xmlrpcmsg XML-RPC Message
 *					0 appkey (string): Unique identifier/passcode of the application sending the post.
 *						(See access info {@link http://www.blogger.com/developers/api/1_docs/#access} .)
 *					1 blogid (string): Unique identifier of the blog the post will be added to.
 *						Currently ignored in b2evo, in favor of the category.
 *					2 username (string): Login for a Blogger user who has permission to post to the blog.
 *					3 password (string): Password for said username.
 *					4 content (string): Contents of the post.
 *					5 publish (boolean): If true, the blog will be published immediately after the
 *						post is made. (In b2evo,this means, the new post will be in 'published' state,
 *						otherwise it would be in draft state).
 * @return xmlrpcresp XML-RPC Response
 */
function blogger_newpost( $m )
{
	global $xmlrpcerruser; // import user errcode value
	global $DB;
	global $Settings, $Messages;

	// CHECK LOGIN:
  /**
	 * @var User
	 */
	if( ! $current_User = & xmlrpcs_login( $m, 2, 3 ) )
	{	// Login failed, return (last) error:
		return xmlrpcs_resperror();
	}

	// GET BLOG:
  /**
	 * @var Blog
	 */
	if( ! $Blog = & xmlrpcs_get_Blog( $m, 1 ) )
	{	// Login failed, return (last) error:
		return xmlrpcs_resperror();
	}

	$content  = $m->getParam(4);
	$content = $content->scalarval();

	$publish  = $m->getParam(5);
	$publish = $publish->scalarval();
	$status = $publish ? 'published' : 'draft';
	logIO("Publish: $publish -> Status: $status");

	$cat_IDs = xmlrpc_getpostcategories( $content );
	if( empty( $cat_IDs ) )
	{ // There were no categories passed in the content:
		if( ! $main_cat = $Blog->get_default_cat_ID() )
		{	// No default category found for requested blog.
			return xmlrpcs_resperror( 12 ); // User error 12
		}
		$cat_IDs = array( $main_cat );
	}
	else
	{
		$main_cat = $cat_IDs[0];
	}

	// CHECK PERMISSION: (we need perm on all categories, especially if they are in different blogs)
	if( ! $current_User->check_perm( 'cats_post!'.$status, 'edit', false, $cat_IDs ) )
	{	// Permission denied
		return xmlrpcs_resperror( 3 );	// User error 3
	}
	logIO( 'Permission granted.' );


	logIO( 'Main cat: '.$main_cat);

	// Check if category exists
	if( get_the_category_by_ID( $main_cat, false ) === false )
	{ // Cat does not exist:
		// fp> TODO use $Blog->get_default_cat_ID();
		return xmlrpcs_resperror( 11 ); // User error 11
	}

	if( get_catblog($main_cat) != $Blog->ID )
	{	// The category does not match the blog!
		return xmlrpcs_resperror( 11 ); // User error 11
	}


	$post_date = date('Y-m-d H:i:s', (time() + $Settings->get('time_difference')));
	// Extract <title> from content
	$post_title = xmlrpc_getposttitle( $content );
	// cleanup content from extra tags like <category> and <title>:
	$content = xmlrpc_removepostdata( $content );


	// COMPLETE VALIDATION & INSERT:
	return xmlrpcs_new_item( $post_title, $content, $post_date, $main_cat, $cat_IDs, $status );
}


$bloggereditpost_doc='Edits a post, blogger-api like';
$bloggereditpost_sig=array(array($xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcBoolean));
/**
 * blogger.editPost changes the contents of a given post.
 *
 * Optionally, will publish the blog the post belongs to after changing the post.
 * (In b2evo, this means the changed post will be moved to published state).
 * On success, it returns a boolean true value.
 * On error, it will return a fault with an error message.
 *
 * @see http://www.blogger.com/developers/api/1_docs/xmlrpc_editPost.html
 * @see http://www.sixapart.com/developers/xmlrpc/blogger_api/bloggereditpost.html
 *
 * @param xmlrpcmsg XML-RPC Message
 *					0 appkey (string): Unique identifier/passcode of the application sending the post.
 *						(See access info {@link http://www.blogger.com/developers/api/1_docs/#access} .)
 *					1 postid (string): Unique identifier of the post to be changed.
 *					2 username (string): Login for a Blogger user who has permission to edit the given
 *						post (either the user who originally created it or an admin of the blog).
 *					3 password (string): Password for said username.
 *					4 content (string): New content of the post.
 *					5 publish (boolean): If true, the blog will be published immediately after the
 *						post is made. (In b2evo,this means, the new post will be in 'published' state,
 *						otherwise it would be in draft state).
 * @return xmlrpcresp XML-RPC Response
 *
 * @todo check current status and permission on it
 */
function blogger_editpost($m)
{
	global $xmlrpcerruser; // import user errcode value
	global $DB;
	global $Messages;

	// CHECK LOGIN:
  /**
	 * @var User
	 */
	if( ! $current_User = & xmlrpcs_login( $m, 2, 3 ) )
	{	// Login failed, return (last) error:
		return xmlrpcs_resperror();
	}

	// GET POST:
  /**
	 * @var Item
	 */
	if( ! $edited_Item = & xmlrpcs_get_Item( $m, 1 ) )
	{	// Failed, return (last) error:
		return xmlrpcs_resperror();
	}

	$content = $m->getParam(4);
	$content = $content->scalarval();

	$publish = $m->getParam(5);
	$publish = $publish->scalarval();
	$status = $publish ? 'published' : 'draft';
	logIO("Publish: $publish -> Status: $status");

	$cat_IDs = xmlrpc_getpostcategories( $content );
	if( empty( $cat_IDs ) )
	{ // There were no categories passed in the content:
		$main_cat = $edited_Item->main_cat_ID;
		$cat_IDs = array( $main_cat );
	}
	else
	{
		$main_cat = $cat_IDs[0];
	}

	// CHECK PERMISSION: (we need perm on all categories, especially if they are in different blogs)
	if( ! $current_User->check_perm( 'cats_post!'.$status, 'edit', false, $cat_IDs ) )
	{	// Permission denied
		return xmlrpcs_resperror( 3 );	// User error 3
	}
	logIO( 'Permission granted.' );

	logIO( 'Main cat: '.$main_cat);

	// Check if category exists
	if( get_the_category_by_ID( $main_cat, false ) === false )
	{ // Cat does not exist:
		// fp> TODO use $Blog->get_default_cat_ID();
		return xmlrpcs_resperror( 11 ); // User error 11
	}

	$post_date = NULL;
	$post_title = xmlrpc_getposttitle($content);
	$content = xmlrpc_removepostdata($content);


	// COMPLETE VALIDATION & UPDATE:
	return xmlrpcs_edit_item( $edited_Item, $post_title, $content, $post_date, $main_cat, $cat_IDs, $status );
}




$bloggerdeletepost_doc = 'Deletes a post, blogger-api like';
$bloggerdeletepost_sig = array(array($xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcBoolean));
/**
 * blogger.deletePost deletes a given post.
 *
 * This API call is not documented on
 * {@link http://www.blogger.com/developers/api/1_docs/}
 * @see http://www.sixapart.com/developers/xmlrpc/blogger_api/bloggerdeletepost.html
 *
 * @param xmlrpcmsg XML-RPC Message
 *					0 appkey (string): Unique identifier/passcode of the application sending the post.
 *						(See access info {@link http://www.blogger.com/developers/api/1_docs/#access} .)
 *					1 postid (string): Unique identifier of the post to be deleted.
 *					2 username (string): Login for a Blogger user who has permission to edit the given
 *						post (either the user who originally created it or an admin of the blog).
 *					3 password (string): Password for said username.
 * @return xmlrpcresp XML-RPC Response
 */
function blogger_deletepost($m)
{
	global $xmlrpcerruser; // import user errcode value
	global $DB;

	// CHECK LOGIN:
	if( ! $current_User = & xmlrpcs_login( $m, 2, 3 ) )
	{	// Login failed, return (last) error:
		return xmlrpcs_resperror();
	}

	// GET POST:
  /**
	 * @var Item
	 */
	if( ! $edited_Item = & xmlrpcs_get_Item( $m, 1 ) )
	{	// Failed, return (last) error:
		return xmlrpcs_resperror();
	}

	// CHECK PERMISSION:
	if( ! $current_User->check_perm( 'blog_del_post', 'any', false, $edited_Item->blog_ID ) )
	{	// Permission denied
		return xmlrpcs_resperror( 3 );	// User error 3
	}
	logIO( 'Permission granted.' );

	// DELETE POST FROM DB:
	$edited_Item->dbdelete();
	if( $DB->error )
	{ // DB error
		return new xmlrpcresp(0, $xmlrpcerruser+9, 'DB error: '.$DB->last_error ); // user error 9
	}

	logIO( 'OK.' );
	return new xmlrpcresp(new xmlrpcval(1));
}



$bloggergetusersblogs_doc='returns the user\'s blogs - this is a dummy function, just so that BlogBuddy and other blogs-retrieving apps work';
$bloggergetusersblogs_sig=array(array($xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString));
/**
 * blogger.getUsersBlogs returns information about all the blogs a given user is a member of.
 *
 * Data is returned as an array of <struct>'s containing the ID (blogid), name (blogName),
 * and URL (url) of each blog.
 *
 * Non official: Also return a boolean stating wether or not the user can edit th eblog templates
 * (isAdmin).
 *
 * see {@link http://www.blogger.com/developers/api/1_docs/xmlrpc_getUsersBlogs.html}
 * @see http://www.sixapart.com/developers/xmlrpc/blogger_api/bloggergetusersblogs.html
 *
 * @param xmlrpcmsg XML-RPC Message
 *					0 appkey (string): Unique identifier/passcode of the application sending the post.
 *						(See access info {@link http://www.blogger.com/developers/api/1_docs/#access} .)
 *					1 username (string): Login for the Blogger user who's blogs will be retrieved.
 *					2 password (string): Password for said username.
 *						(currently not required by b2evo)
 * @return xmlrpcresp XML-RPC Response, an array of <struct>'s containing for each blog:
 *					- ID (blogid),
 *					- name (blogName),
 *					- URL (url),
 *					- bool: can user edit template? (isAdmin).
 */
function blogger_getusersblogs($m)
{
	global $xmlrpcerruser;
	global $baseurl;

	// CHECK LOGIN:
	if( ! $current_User = & xmlrpcs_login( $m, 1, 2 ) )
	{	// Login failed, return (last) error:
		return xmlrpcs_resperror();
	}

	// LOAD BLOGS tehuser is a member of:
	$BlogCache = & get_Cache( 'BlogCache' );
	$blog_array = $BlogCache->load_user_blogs( 'blog_ismember', 'view', $current_User->ID, 'ID' );

	$resp_array = array();
	foreach( $blog_array as $l_blog_ID )
	{	// Loop through all blogs that match the requested permission:

		/**
		 * @var Blog
		 */
		$l_Blog = & $BlogCache->get_by_ID( $l_blog_ID );

		logIO("Current user IS a member of this blog.".$l_blog_ID);

		$resp_array[] = new xmlrpcval( array(
					"blogid" => new xmlrpcval( $l_blog_ID ),
					"blogName" => new xmlrpcval( $l_Blog->get('shortname') ),
					"url" => new xmlrpcval( $l_Blog->gen_blogurl() ),
					"isAdmin" => new xmlrpcval( $current_User->check_perm( 'templates', 'any' ), 'boolean')
												), 'struct');
	}

	$resp = new xmlrpcval($resp_array, 'array');

	logIO( 'OK.' );
	return new xmlrpcresp($resp);
}




$bloggergetuserinfo_doc='gives the info about a user';
$bloggergetuserinfo_sig=array(array($xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString));
/**
 * blogger.getUserInfo returns returns a struct containing user info.
 *
 * Data returned: userid, firstname, lastname, nickname, email, and url.
 *
 * see {@link http://www.blogger.com/developers/api/1_docs/xmlrpc_getUserInfo.html}
 * @see http://www.sixapart.com/developers/xmlrpc/blogger_api/bloggergetuserinfo.html
 *
 * @param xmlrpcmsg XML-RPC Message
 *					0 appkey (string): Unique identifier/passcode of the application sending the post.
 *						(See access info {@link http://www.blogger.com/developers/api/1_docs/#access} .)
 *					1 username (string): Login for the Blogger user who's blogs will be retrieved.
 *					2 password (string): Password for said username.
 *						(currently not required by b2evo)
 * @return xmlrpcresp XML-RPC Response, a <struct> containing:
 *					- userid,
 *					- firstname,
 *					- lastname,
 *					- nickname,
 *					- email,
 *					- url
 */
function blogger_getuserinfo($m)
{
	global $xmlrpcerruser;

	// CHECK LOGIN:
	if( ! $current_User = & xmlrpcs_login( $m, 1, 2 ) )
	{	// Login failed, return (last) error:
		return xmlrpcs_resperror();
	}

	// INFO about looged in user
	$struct = new xmlrpcval( array(
			'nickname'  => new xmlrpcval( $current_User->get('nickname') ),
			'userid'    => new xmlrpcval( $current_User->ID ),
			'url'       => new xmlrpcval( $current_User->get('url') ),
			'email'     => new xmlrpcval( $current_User->get('email') ),
			'lastname'  => new xmlrpcval( $current_User->get('lastname') ),
			'firstname' => new xmlrpcval( $current_User->get('firstname') )
		), 'struct' );

	logIO( 'OK.' );
	return new xmlrpcresp( $struct );
}




$bloggergetpost_doc = 'fetches a post, blogger-api like';
$bloggergetpost_sig = array(array($xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString));
/**
 * blogger.getPost retieves a given post.
 *
 * This API call is not documented on
 * {@link http://www.blogger.com/developers/api/1_docs/}
 * @see http://www.sixapart.com/developers/xmlrpc/blogger_api/bloggergetpost.html
 *
 * @param xmlrpcmsg XML-RPC Message
 *					0 appkey (string): Unique identifier/passcode of the application sending the post.
 *						(See access info {@link http://www.blogger.com/developers/api/1_docs/#access} .)
 *					1 postid (string): Unique identifier of the post to be deleted.
 *					2 username (string): Login for a Blogger user who has permission to edit the given
 *						post (either the user who originally created it or an admin of the blog).
 *					3 password (string): Password for said username.
 * @return xmlrpcresp XML-RPC Response
 */
function blogger_getpost($m)
{
	global $xmlrpcerruser;

	// CHECK LOGIN:
  /**
	 * @var User
	 */
	if( ! $current_User = & xmlrpcs_login( $m, 2, 3 ) )
	{	// Login failed, return (last) error:
		return xmlrpcs_resperror();
	}

	// GET POST:
  /**
	 * @var Item
	 */
	if( ! $edited_Item = & xmlrpcs_get_Item( $m, 1 ) )
	{	// Failed, return (last) error:
		return xmlrpcs_resperror();
	}

	// CHECK PERMISSION: (we need at least one post/edit status)
	// (we should be able to see even if we cannot edit the particular status of that post)
	if( ! $current_User->check_perm( 'blog_post_statuses', 1, false, $edited_Item->blog_ID ) )
	{	// Permission denied
		return xmlrpcs_resperror( 3 );	// User error 3
	}
	logIO( 'Permission granted.' );


	$post_date = mysql2date( "U", $edited_Item->issue_date );
	$post_date = gmdate("Ymd", $post_date)."T".gmdate("H:i:s", $post_date);

	$content	= '<title>'.$edited_Item->title.'</title>';
	$content .= '<category>'.$edited_Item->main_cat_ID.'</category>';
	$content .= $edited_Item->content;

	$struct = new xmlrpcval( array(
									'userid'      => new xmlrpcval( $edited_Item->creator_user_ID ),
									'dateCreated' => new xmlrpcval( $post_date, 'dateTime.iso8601' ),
									'content'     => new xmlrpcval( $content ),
									'postid'      => new xmlrpcval( $edited_Item->ID )
								), "struct" );

	logIO( 'OK.' );
	return new xmlrpcresp($struct);
}




$bloggergetrecentposts_doc = 'fetches X most recent posts, blogger-api like';
$bloggergetrecentposts_sig = array(array($xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcString, $xmlrpcInt));
/**
 * blogger.getRecentPosts retieves X most recent posts.
 *
 * This API call is not documented on
 * {@link http://www.blogger.com/developers/api/1_docs/}
 * @see http://www.sixapart.com/developers/xmlrpc/blogger_api/bloggergetrecentposts.html
 *
 * @param xmlrpcmsg XML-RPC Message
 *					0 appkey (string): Unique identifier/passcode of the application sending the post.
 *						(See access info {@link http://www.blogger.com/developers/api/1_docs/#access} .)
 *					1 blogid (string): Unique identifier of the blog the post will be added to.
 *						Currently ignored in b2evo, in favor of the category.
 *					2 username (string): Login for a Blogger user who has permission to edit the given
 *						post (either the user who originally created it or an admin of the blog).
 *					3 password (string): Password for said username.
 *					4 numposts (integer): number of posts to retrieve.
 * @return xmlrpcresp XML-RPC Response
 */
function blogger_getrecentposts( $m )
{
	global $xmlrpcerruser, $DB;

	// CHECK LOGIN:
  /**
	 * @var User
	 */
	if( ! $current_User = & xmlrpcs_login( $m, 2, 3 ) )
	{	// Login failed, return (last) error:
		return xmlrpcs_resperror();
	}

	// GET BLOG:
  /**
	 * @var Blog
	 */
	if( ! $Blog = & xmlrpcs_get_Blog( $m, 1 ) )
	{	// Login failed, return (last) error:
		return xmlrpcs_resperror();
	}

	// CHECK PERMISSION: (we need at least one post/edit status)
	// (we should be able to see all even if we cannot edit the particular status of a post)
	if( ! $current_User->check_perm( 'blog_post_statuses', 1, false, $Blog->ID ) )
	{	// Permission denied
		return xmlrpcs_resperror( 3 );	// User error 3
	}
	logIO( 'Permission granted.' );


	$numposts = $m->getParam(4);
	$numposts = $numposts->scalarval();


	// Get the posts to display:
	load_class( 'items/model/_itemlist.class.php' );
	$MainList = & new ItemList2( $Blog, NULL, NULL, $numposts );

	$MainList->set_filters( array(
			'visibility_array' => array( 'published', 'protected', 'private', 'draft', 'deprecated', 'redirected' ),
			'order' => 'DESC',
			'unit' => 'posts',
		) );

	// Run the query:
	$MainList->query();


	xmlrpc_debugmsg( 'Items:'.$MainList->result_num_rows );

	$data = array();
	while( $Item = & $MainList->get_item() )
	{
		xmlrpc_debugmsg( 'Item:'.$Item->title.
											' - Issued: '.$Item->issue_date.
											' - Modified: '.$Item->mod_date );

		$post_date = mysql2date("U", $Item->issue_date);
		$post_date = gmdate("Ymd", $post_date)."T".gmdate("H:i:s", $post_date);

		$content	= '<title>'.$Item->title.'</title>';
		$content .= '<category>'.$Item->main_cat_ID.'</category>';
		$content .= $Item->content;

		// Load Item's creator User:
		$Item->get_creator_User();
		$authorname = $Item->creator_User->get('preferredname');

		$data[] = new xmlrpcval(array(
									"authorName" => new xmlrpcval($authorname),
									"userid" => new xmlrpcval($Item->creator_user_ID),
									"dateCreated" => new xmlrpcval($post_date,"dateTime.iso8601"),
									"content" => new xmlrpcval($content),
									"postid" => new xmlrpcval($Item->ID)
									),"struct");
	}

	$resp = new xmlrpcval($data, "array");

	logIO( 'OK.' );
	return new xmlrpcresp($resp);
}


$xmlrpc_procs["blogger.newPost"] = array(
				"function" => "blogger_newpost",
				"signature" => $bloggernewpost_sig,
				"docstring" => $bloggernewpost_doc );

$xmlrpc_procs["blogger.editPost"] = array(
				"function" => "blogger_editpost",
				"signature" => $bloggereditpost_sig,
				"docstring" => $bloggereditpost_doc );

$xmlrpc_procs["blogger.deletePost"] = array(
				"function" => "blogger_deletepost",
				"signature" => $bloggerdeletepost_sig,
				"docstring" => $bloggerdeletepost_doc );

$xmlrpc_procs["blogger.getUsersBlogs"] = array(
				"function" => "blogger_getusersblogs",
				"signature" => $bloggergetusersblogs_sig,
				"docstring" => $bloggergetusersblogs_doc );

$xmlrpc_procs["blogger.getUserInfo"] = array(
				"function" => "blogger_getuserinfo",
				"signature" => $bloggergetuserinfo_sig,
				"docstring" => $bloggergetuserinfo_doc );

$xmlrpc_procs["blogger.getPost"] = array(
				"function" => "blogger_getpost",
				"signature" => $bloggergetpost_sig,
				"docstring" => $bloggergetpost_doc );

$xmlrpc_procs["blogger.getRecentPosts"] = array(
				"function" => "blogger_getrecentposts",
				"signature" => $bloggergetrecentposts_sig,
				"docstring" => $bloggergetrecentposts_doc );


?>