<?php 
/**
 * Implements the blogger and MetaWeblog APIs.
 *
 * @package pivot
 */
/* 
 *  Blogger and metaWeblog implementation for Pivot
 *
 *  Based on phpMyWeblog's api.php
 *
 *  Initially modified by Connor Carney to work with Pivot
 *  Revamped, corrected and extended by the Pivot team.
 *
 *  Originally Created by Dougal Campbell <dougal@gunters.org>, <emc3@users.sf.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */


/**
 * Including Pivot core functions and XML RPC functions/server.
 */
include_once('pv_core.php');
require_once('includes/xmlrpc/xmlrpc.inc');
require_once('includes/xmlrpc/xmlrpcs.inc');;

/**
 * Selecting UTF-8 as default encoding. If the current Pivot isn't
 * using UTF-8, we use i18n_array_to_utf8 and i18n_array_from_utf8
 * to go back and forth.
 */
$xmlrpc_internalencoding = 'UTF-8';

$db=new db();
$conversion_method=0;
$VerboseGenerate = false;


// PIVOT FUNCTIONS
// These functions update the pivot database using the data
// from XMLRPC:

/**
 * Separator for introduction and body parts of an entry
 */
$body_separator = "PIVOT_BODY";

/** 
 * Checks username and password, and return an array with
 * the userid (uid) and potentially an error (err).
 *
 * @param string $user
 * @param string $pass
 * @return array
 */
function pivot_get_userid($user,$pass) {
	global $Cfg, $Users;
	
	if (!$Cfg['xmlrpc']) {
		debug("XML-RPC is disabled. Method call from ".$_SERVER['REMOTE_ADDR']." ignored.");
		return array(
			'uid'=>-1,
			'err'=>"XML-RPC is disabled."
		);
	}

	if($Cfg['fl_' . $_SERVER['REMOTE_ADDR']] >= 10 && ($Cfg['bn_' . $_SERVER['REMOTE_ADDR']] - time() < 60*60*12)){
		if(!isset($Cfg['bn_' . $_SERVER['REMOTE_ADDR']])){
			$Cfg['bn_' . $_SERVER['REMOTE_ADDR']] = time();
		}
		SaveSettings();
		debug("IP is banned. Method call from ".$_SERVER['REMOTE_ADDR']." ignored.");
		return array(
			'uid'=>-1,
			'err'=>"IP is banned."
		);
	}

	
	if ($Users[$user]['pass'] == md5($pass)) {
		debug("User $user approved");
		return array('uid'=>$user);
	}else{
		// add one to the failed login attempts.
		if(strlen($user) > 0) {
			$Cfg['fl_' . $_SERVER['REMOTE_ADDR']]++;
			SaveSettings();
		}
		debug("Wrong password/username ($user)");
		return array(
			'uid'=>-1,
			'err'=>"Your password/username is incorrect."
		);
	}
}
/**
 * Creates a list of categories (with description and more properties) for 
 * the given blog ID.
 * 
 * @param string $blogid
 * @return array
 */
function pivot_get_blog_cats($blogid) {
	global $Paths;
	$cats = find_cats_in_weblog($blogid);
	$cats_info = array();
	foreach ($cats as $cat) {
		// (categoryid is needed by Windows Live Writer.)
		$cats_info[] = array(
			'description'=>$cat,
			'title'=>$cat,
			'categoryid'=>$cat,
			'htmlUrl'=>$Paths['host'].$Paths['pivot_url']."archive.php?c=".para_category($cat)
			// 'rssURL'=>$Paths['host'].$Paths['pivot_url']."archive.php?c=".para_category($cat)
		);
	}
	i18n_array_to_utf8($cats_info, $dummy, true);
	return $cats_info;
}

/**
 * Finds the list of blogs (without checking the user permissions).
 *
 * @param string $uid
 * @return array
 */
function pivot_get_user_blogs($uid) {
	global $Weblogs, $Current_weblog, $Users, $Paths;
	$Current_weblog_orig = $Current_weblog;
	$ThisUser = $Users[$uid];
	$blogs = array();
	foreach ($Weblogs as $key => $value) {
		$Current_weblog = $key;
		$blogs[] = array(
			"blogid"=>$key,
			"blogName"=>snippet_weblogtitle(),
			"url"=>$Paths['host'].snippet_home()
		);
	}
	$Current_weblog = $Current_weblog_orig;
	i18n_array_to_utf8($blogs, $dummy, true);
	return $blogs;
}


/**
 * Determines if a user can post to a given blog (at all) by checking all 
 * permissions for all categories.
 *
 * @param string $uid
 * @param string $blogid
 * @return boolean
 */
function pivot_user_blog_check($uid,$blogid) {
	global $Users, $Cfg;
	$ThisUser = $Users[$uid];
	$cats = find_cats_in_weblog($blogid);
	foreach ($cats as $cat) {
		$allowed = explode("|", $Cfg['cat-'. $cat]);
		if (in_array($uid, $allowed)){
			debug("User $uid allowed to post in blog $blogid");
			return true;
		}
	}
	debug("User $uid NOT allowed to post to any category in blog $blogid");
	return false;
}


/** 
 * Determines if a post exists.
 *
 * @param string $postid
 * @return boolean
 */
function pivot_post_exists($postid) {
	global $db;
	$entry=$db->read_entry($postid);
	if (!isset($entry['code']) || empty($entry['code'])) {
		return false;
	} else {
		return true;
	}
}

/** 
 * Determines if a user has access to a given post.
 *
 * @todo Check if user is administrator or super-user.
 *
 * @param string $uid
 * @param string $postid
 * @return boolean
 */
function pivot_user_post_check($uid,$postid) {
	global $db;
	$entry=$db->read_entry($postid);
	if ($entry['user']!=$uid){
		return false;
	} else {
		return true;
	}
}

/**
 * Finds recent posts in the given blog.
 *
 * @param string $blogid
 * @param string $num
 * @return array
 */
function pivot_recent($blogid,$num) {
	global $Paths, $db, $body_separator;

	$postlist=$db->getlist(-$num,0,"", find_cats_in_weblog($blogid), FALSE, "");
	
	$retposts=array();
	foreach($postlist as $post){
		$thispost= $db->read_entry($post['code']);
		$content = $thispost['introduction'];
		if(!empty($thispost['body'])) {
			$content = $content."\n".$body_separator."\n".$thispost['body'];
		}
		$retposts[]=array(
			'date'=>$thispost['date'],
			'userid'=>$thispost['user'],
			'postid'=>$thispost['code'],
			'content'=>$content,
			'title'=>$thispost['title'],
			'description'=>$content,
			'link'=>$Paths['host'].$Paths['pivot_url'].'entry.php?id='.$thispost['code'],
			'permalink'=>$Paths['host'].$Paths['pivot_url'].'entry.php?id='.$thispost['code'],
			'categories'=>$thispost['category']
		);
	}
	i18n_array_to_utf8($retposts, $dummy, true);
	return $retposts;
}


/**
 * Get a specific post.
 *
 * @todo Fix links (use functions). Add user check?
 *
 * @param string $postid
 * @return array
 */
function pivot_get_post($postid) {
	global $db, $Paths, $body_separator;
	
	$post=$db->read_entry($postid);
	list($yr,$mo,$da,$ho,$mi)=split("-",$post['date']);
	$unixtime = mktime($ho,$mi,0,$mo,$da,$yr);
	$isoString=iso8601_encode($unixtime);
	$content = $post['introduction'];
	if(!empty($post['body'])) {
		$content = $content."\n".$body_separator."\n".$post['body'];
	}
	$result = array(
		'dateCreated'=>new xmlrpcval($isoString,"dateTime.iso8601"),
		'userid'=>$post['user'],
		'postid'=>$post['code'],
		'content'=>$content,
		'title'=>$post['title'],
		'description'=>$post['introduction'],
		'link'=>$Paths['host'].$Paths['pivot_url'].'entry.php?id='.$post['code'],
		'permaLink'=>$Paths['host'].$Paths['pivot_url'].'entry.php?id='.$post['code'],
		'categories'=>$post['category']
	);
		
	i18n_array_to_utf8($result, $dummy, true);
	return $result;
}

/**
 * Creates a new post and returns the code for that entry,.
 *
 * @param string $uid
 * @param string $title
 * @param string $body
 * @param string $categories
 * @return int
 */
function pivot_new_post($uid,$title,$body,$categories) {
	global $db, $conversion_method, $body_separator;
	
	$entry['code'] = ">";
		
	$entry['date'] = date("Y-m-d-H-i", get_current_date());

	list($pivotintro,$pivotbody) = explode($body_separator, strip_trailing_space(stripslashes($body)));
	$entry['introduction'] = $pivotintro;
	$entry['body'] = $pivotbody;
	
	$entry['introduction'] = tidy_html($entry['introduction'], TRUE);
	$entry['body'] = tidy_html($entry['body'], TRUE);
	
	$entry['category'] = $categories;
	$entry['publish_date'] = date("Y-m-d-H-i", get_current_date());
	$entry['edit_date'] = date("Y-m-d-H-i");
	$entry['title'] = strip_trailing_space(stripslashes($title));
	$entry['subtitle'] = "";
	$entry['user'] = $uid;
	$entry['convert_lb'] = $conversion_method;
	$entry['status'] =  "publish";
	$entry['allow_comments'] = 1;
	$entry['keywords'] = "";
	$entry['vialink'] =  "";
	$entry['viatitle'] = "";
	
	$db->set_entry($entry);
	$db->save_entry(TRUE);

	generate_pages( $db->entry['code'],TRUE,TRUE,TRUE,FALSE);
	
	//Return code
	return $db->entry['code'];
}


/**
 * Updates a post.
 *
 * @param string $uid
 * @param string $postid
 * @param string $title
 * @param string $content
 * @param array $categories
 * @return void
 */
function pivot_update_post($uid,$postid,$title,$content,$categories='') {
	global $db, $conversion_method, $body_separator;
	
	$oldentry = $db->read_entry($postid);
	
	$entry['code'] = $postid;
	
	$entry['date'] = $oldentry['date'];
	list($pivotintro,$pivotbody) = explode($body_separator, strip_trailing_space(stripslashes($content)));
	$entry['introduction'] = $pivotintro;
	$entry['body'] = $pivotbody;
	$entry['introduction'] = tidy_html($entry['introduction'], TRUE);
	$entry['body'] = tidy_html($entry['body'], TRUE);
	if (empty($categories)) {
		$entry['category'] = $oldentry['category'];
	} else {
		$entry['category'] = $categories;
	}
	$entry['publish_date'] = $oldentry['publish_date'];
	$entry['edit_date'] = date("Y-m-d-H-i", get_current_date());
	$entry['title'] = strip_trailing_space(stripslashes($title));
	$entry['subtitle'] = $oldentry['subtitle'];
	$entry['user'] = $uid;
	$entry['convert_lb'] = $conversion_method;
	$entry['status'] =  "publish";
	$entry['allow_comments'] = 1;
	$entry['keywords'] = $oldentry['keywords'];
	$entry['vialink'] =  $oldentry['vialink'];
	$entry['viatitle'] = $oldentry['viatitle'];
	
	$db->set_entry($entry);
	$db->save_entry(TRUE);
	
	generate_pages( $db->entry['code'],TRUE,TRUE,TRUE,FALSE);
}

/**
 * Deletes a post.
 *
 * @param string $postid
 * @return void
 */
function pivot_delete_post($postid) {
	global $db;
	$entry = $db->read_entry($postid);
	$db->delete_entry();
	
	$overview_arr = $db->getlist(-4,0,"","", FALSE);
	
	foreach ($overview_arr as $entry) {
		generate_pages($entry['code'], TRUE, TRUE, TRUE, FALSE);
	}
}


/**
 * Returns info about user.
 *
 * @todo Fetch more info (if possible) from global $Users array.
 *
 * @param string $uid
 * @return array
 */
function pivot_user_info($uid) {

	$info = array(	
	'userid' => $uid,
	'firstname' => '',
	'lastname' => '',
	'nickname' => $uid,
	'email' => '',
	'url' => ''
	);

	i18n_array_to_utf8($info, $dummy, true);
	return $info;
}

/***********************************************************************************************
 * Blogger API
 *
 * MetaWeblog is based on Blogger, so we have to include these.
 * Posting via Blogger clients might work, but isn't recommended or tested.
 */

/**
 * blogger.newPost
 *
 * @param array $params Contains application key (ignored), blog id, username, password, content, and publish status (ignored). 
 */
function newPost ($params) {
	global $Cfg, $xmlrpcerruser;

	$conv = $params->getParam(0); $appkey = $conv->scalarval();
	$conv = $params->getParam(1); $blogid = $conv->scalarval();
	$conv = $params->getParam(2); $user = $conv->scalarval();
	$conv = $params->getParam(3); $pass = $conv->scalarval();
	$conv = $params->getParam(4); $content = $conv->scalarval();
	$conv = $params->getParam(5); $publish = $conv->scalarval();

	i18n_array_from_utf8($content,$dummy);

	// Make Sure User Name and Password Match
	$login = pivot_get_userid($user,$pass);

	//Get the User ID
	$uid = $login['uid'];
	
	if ($uid != -1) {
		//Check access rights
		if (!pivot_user_blog_check($uid,$blogid)) {
			$err = "User " . $user . " does not have access to any category in blog " . $blogid;
		}

	} else {
		//Throw an error if the password was wrong.
		$err = $login['err'];
	}

	if ($err) {
		// Return an Error
		return new xmlrpcresp(0, $xmlrpcerruser+1,$err);
	} else {

		// Let's try using <title> tags....
		// Blogger has no built-in title feature.  You should use MetaWeblog instead.
		$result = preg_match('/<title>(.+)<\/title>(.*)/is',$content,$arr);
		if ($result) {
			$title = $arr[1];
			$body = $arr[2];
		} else {
			$title = '';
			$body = $content;
		}

		// Finding (first) allowed category in selected blog
		$categories = array();
		$cats = find_cats_in_weblog($blogid);
		foreach ($cats as $cat) {
			$allowed = explode("|", $Cfg['cat-'. $cat]);
			if (in_array($uid, $allowed)){
				$categories[] = $cat;
				break;
			}
		}
		if (count($categories) == 0) {
			return new xmlrpcresp(0, $xmlrpcerruser+1,
				"User $user does not have access to any category in blog $blogid");
		} else { 
			$postid = pivot_new_post($uid,$title,$body,$categories);
			$myResp = new xmlrpcval($postid,"string");
			return new xmlrpcresp($myResp);
		}
	}
}

/**
 * blogger.editPost
 *
 * @param array $params Contains application key (ignored), post id, username, password, content, and publish status (ignored)
 */
function editPost ($params) {
	global $xmlrpcerruser;


	$conv = $params->getParam(0); $appkey = $conv->scalarval();
	$conv = $params->getParam(1); $postid = $conv->scalarval();
	$conv = $params->getParam(2); $user = $conv->scalarval();
	$conv = $params->getParam(3); $pass = $conv->scalarval();
	$conv = $params->getParam(4); $content = $conv->scalarval();
	$conv = $params->getParam(5); $publish = $conv->scalarval();

	i18n_array_from_utf8($content,$dummy);

	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];
	
	if ($uid != -1) {
		if (!pivot_post_exists($postid)) {
			$err = "Post $postid doesn't exist";
		} else if (!pivot_user_post_check($uid,$postid)) {
			$err = "$user didn't write $postid";
		} 
	} else {
		$err = $login['err'];
	}
	
	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1,$err);
	} else {
		// Let's try using <title> tags....
		$result = preg_match('/^<title>(.+)<\/title>(.*)/is',$content,$arr);
		if ($result) {
			$title = $arr[1];
			$body = $arr[2];
		} else {
			$title = '';
			$body = $content;
		}

		pivot_update_post($uid,$postid,$title,$body);
		
		$myResp = new xmlrpcval(1,"boolean");

		// return
		return new xmlrpcresp($myResp);
	}
}

/**
 * blogger.getPost
 *
 * @param array $params Containsapplication key (ignored), post id, username, and password
 */
function getPost ($params) {

	$conv = $params->getParam(0); $appkey = $conv->scalarval();
	$conv = $params->getParam(1); $postid = $conv->scalarval();
	$conv = $params->getParam(2); $user = $conv->scalarval();
	$conv = $params->getParam(3); $pass = $conv->scalarval();

	// Check password
	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];
	
	if ($uid != -1) {
		if (!pivot_post_exists($postid)) {
			$err = "Post $postid doesn't exist";
		} else {
			$xmlrpcpost = pivot_get_post($postid);
		}
	} else {
		$err = $login['err'];
	}

	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1,$err);
	} else {
		//Return a response
		$myResp = new xmlrpcval($xmlrpcpost,"struct");
		return new xmlrpcresp($myResp);
	}

}


/**
 * blogger.deletePost
 *
 * @param array $params Contains application key (ignored), post id, username, password, and publish status (ignored)
 */
function deletePost ($params) {
	global $xmlrpcerruser;

	$conv = $params->getParam(0); $appkey = $conv->scalarval();
	$conv = $params->getParam(1); $postid = $conv->scalarval();
	$conv = $params->getParam(2); $user = $conv->scalarval();
	$conv = $params->getParam(3); $pass = $conv->scalarval();
	$conv = $params->getParam(4); $publish = $conv->scalarval();
	
	// Check password
	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];
	
	if ($uid != -1) {
		if (!pivot_post_exists($postid)) {
			$err = "Post $postid doesn't exist";
		} else if (!pivot_user_post_check($uid,$postid)) {
			$err = "$user didn't write $postid";
		} else {
			$err = pivot_delete_post($postid);
		}
	} else {
		$err = $login['err'];
	}

	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1,$err);
	} else {
		$myResp = new xmlrpcval(1,"boolean");
		return new xmlrpcresp($myResp);
	}

}


/**
 * blogger.getRecentPosts
 *
 * @param array $params Contains application key (ignored), blog ID, username, password, and number of posts
 */
function getRecentPosts ($params) {	// ($appkey, $blogid, $user, $pass, $num) 
	global $xmlrpcerruser;

	$conv = $params->getParam(0); $appkey = $conv->scalarval();
	$conv = $params->getParam(1); $blogid = $conv->scalarval();
	$conv = $params->getParam(2); $user = $conv->scalarval();
	$conv = $params->getParam(3); $pass = $conv->scalarval();
	$conv = $params->getParam(4); $num = $conv->scalarval();

	// Check password
	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];
	
	if ($uid != -1) {
		//Check Permissions
		if (pivot_user_blog_check($uid,$blogid)) {
			$postlist = pivot_recent($blogid,$num);
		} else {
			$err = "$user does not have access to any category in blog $blogid";
		}

	} else {
		$err = $login['err'];
	}

	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1,$err);
	} else {
		// Encode each entry of the array.
		foreach($postlist as $entry) {
			// convert the date
			list($yr,$mo,$da,$ho,$mi)=split("-",$entry['date']);
			$unixtime = mktime($ho,$mi,0,$mo,$da,$yr);
			$isoString=iso8601_encode($unixtime);
			$date = new xmlrpcval($isoString,"dateTime.iso8601");
			
			$userid = new xmlrpcval($entry['userid']);
			$postid = new xmlrpcval($entry['postid']);
			$content = new xmlrpcval($entry['content']);

			$encode_arr = array(
				'dateCreated' => $date,
				'userid' => $userid,
				'postid' => $postid,
				'content' => $content
			);
			
			$xmlrpcpostarr[] = new xmlrpcval($encode_arr,"struct");
		}	

		$myResp = new xmlrpcval($xmlrpcpostarr,"array");

		return new xmlrpcresp($myResp);
	}

}


/**
 * blogger.getUserInf
 *
 * @param array $params Contains application key (ignored), username and password.
 */
function getUserInf ($params) {
	global $xmlrpcerruser;

	$conv = $params->getParam(0); $appkey = $conv->scalarval();
	$conv = $params->getParam(1); $user = $conv->scalarval();
	$conv = $params->getParam(2); $pass = $conv->scalarval();

	// Check password
	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];
	
	if ($uid == -1) {
		$err = $login['err'];
	}

	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1,$err);
	} else {
		$xmlrpcuser = pivot_user_info($uid);
		$myResp = php_xmlrpc_encode($xmlrpcuser);
		return new xmlrpcresp($myResp);
	}

}


/**
 * blogger.getUsersBlogs and metaWeblog.getUsersBlogs
 *
 * @param array $params Contains application key (ignored), username, and password
 */
function getUsersBlogs ($params) {
	global $xmlrpcerruser;

	$conv = $params->getParam(0); $appkey = $conv->scalarval();
	$conv = $params->getParam(1); $user = $conv->scalarval();
	$conv = $params->getParam(2); $pass = $conv->scalarval();
	

	// Check password
	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];
	
	if ($uid != -1) {
		$bloglist = pivot_get_user_blogs($uid);
				
		if (!is_array($bloglist)) {
			$err = "$user isn't allowed to post here.";
		}

	} else {
		$err = $login['err'];
	}

	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1, $err);
	} else {
		//Make an array of blogs
		foreach($bloglist as $entry) {
			$xmlrpcblogarr[] = php_xmlrpc_encode($entry);
		}	

		// Convert the array to XMLRPC
		$myResp = new xmlrpcval($xmlrpcblogarr,"array");

		// return
		return new xmlrpcresp($myResp);
	}
}


/**
 * blogger.getTemplate
 *
 * We don't support template editing, so we just return an error.
 *
 * @param array $params Contains application key, blog id, username, password
 */
function getTemplate ($params) {	 
	global $xmlrpcerruser;

	$err = "this endpoint doesn't support template editing.";

	return new xmlrpcresp(0, $xmlrpcerruser+1, $err);
}

/**
 * blogger.getTemplate
 *
 * We don't support template editing, so we just return an error.
 *
 * @param array $params Contains application key, blog id, username, password, template, and type
 */
function setTemplate ($params) {	// ($appkey, $blogid, $user, $pass, $template, $type) 
	global $xmlrpcerruser;

	$err = "this endpoing doesn't support template editing.";
	

	return new xmlrpcresp(0, $xmlrpcerruser+1, $err);
}


/**********************************************************************************************
 * MetaWeblog Functions
 */

/**
 * metaWeblog.newPost
 *
 * @param array $params Contains blog id, username, password, content, and publish status.
 */
function metaweblog_newPost($params) {
	global $Cfg, $xmlrpcerruser;

	$conv = $params->getParam(0); $blogid = $conv->scalarval();
	$conv = $params->getParam(1); $user = $conv->scalarval();
	$conv = $params->getParam(2); $pass = $conv->scalarval();
	$conv = $params->getParam(3); $contentstruct = php_xmlrpc_decode($conv);
	$conv = $params->getParam(4); $conv = $conv->scalarval();

	i18n_array_from_utf8($contentstruct,$dummy);

	// Check password
	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];
	
	if ($uid != -1) {
		if (!pivot_user_blog_check($uid,$blogid)) {
			$err = "User " . $user . " does not have access to any category in blog " . $blogid;
		}
	} else {
		$err = $login['err'];
	}

	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1, $err);
	} else {
		//Create post and respond

		$title = $contentstruct['title'];
		$content = $contentstruct['description'];
		if (!isset($contentstruct['categories']) ||
			(count($contentstruct['categories']) == 0)) {
			// Finding (first) allowed category in selected blog
			$categories = array();
			$cats = find_cats_in_weblog($blogid);
			foreach ($cats as $cat) {
				$allowed = explode("|", $Cfg['cat-'. $cat]);
				if (in_array($uid, $allowed)){
					$categories[] = $cat;
					break;
				}
			}
		} else {
			$categories = $contentstruct['categories'];
			// Checking if submitted categories really belong to selected blog.
			$cats = find_cats_in_weblog($blogid);
			foreach ($categories as $key => $value) {
				if (!in_array($value,$cats)) {
					unset($categories[$key]);
					debug("Category $value doesn't belong to weblog $blogid");
				}
			}
			if (count($categories) == 0) {
				$err = "None of the entry's categories belong to the selected blog";
				return new xmlrpcresp(0, $xmlrpcerruser+1, $err);
			}
		}

		$postid = pivot_new_post($uid,$title,$content,$categories);
		
		$myResp = new xmlrpcval($postid,"string");
		return new xmlrpcresp($myResp);
	}

}


/**
 * metaWeblog.editPost
 *
 * @param array $params Contains post id, user, password, content and publish
 */
function metaweblog_editPost ($params) {
	global $xmlrpcerruser;

	$conv = $params->getParam(0); $postid = $conv->scalarval();
	$conv = $params->getParam(1); $user = $conv->scalarval();
	$conv = $params->getParam(2); $pass = $conv->scalarval();
	$conv = $params->getParam(3); $contentstruct = php_xmlrpc_decode($conv);
	$conv = $params->getParam(4); $publish = $conv->scalarval();

	i18n_array_from_utf8($contentstruct,$dummy);
	
	// Check password
	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];
	
	if ($uid != -1) {
		if (!pivot_post_exists($postid)) {
			$err = "Post $postid doesn't exist";
		} else if (!pivot_user_post_check($uid,$postid)) {
			$err = "$user didn't write post $postid";
		}
	} else {
		$err = $login['err'];
	}
	
	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1, $err);
	} else {
		//Update the post and return
		
		$title = $contentstruct['title'];
		$content = $contentstruct['description'];
		$categories = $contentstruct['categories'];
		pivot_update_post($uid,$postid,$title,$content,$categories);
		
		$myResp = new xmlrpcval(1,"boolean");

		return new xmlrpcresp($myResp);
	}
}


/**
 * metaWeblog.getPost
 *
 * @param array $params Contains post id, username, password
 */
function metaweblog_getPost ($params) {
	$conv = $params->getParam(0); $postid = $conv->scalarval();
	$conv = $params->getParam(1); $user = $conv->scalarval();
	$conv = $params->getParam(2); $pass = $conv->scalarval();

	// Check password
	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];

	if ($uid != -1) {
		if (!pivot_post_exists($postid)) {
			$err = "Post $postid doesn't exist";
		} else {
			$xmlrpcpost = pivot_get_post($postid);
		}

	} else {
		$err = $login['err'];
	}

	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1, $err);
	} else {
		//Encode as an XMLRPC array
		$myResp = php_xmlrpc_encode($xmlrpcpost);
		
		return new xmlrpcresp($myResp);
	}

}


/**
 * metaWeblog.getRecentPosts
 *
 * @param array $params Contains blog id, username, password, and number of posts
 */
function metaweblog_getRecentPosts ($params) {
	global $xmlrpcerruser;

	$conv = $params->getParam(0); $blogid = $conv->scalarval();
	$conv = $params->getParam(1); $user = $conv->scalarval();
	$conv = $params->getParam(2); $pass = $conv->scalarval();
	$conv = $params->getParam(3); $num = $conv->scalarval();

	// Check password
	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];
	
	if ($uid != -1) {
		// Check blog permissions.
		if (pivot_user_blog_check($uid,$blogid)) {
			$postlist = pivot_recent($blogid,$num);
		} else {
			$err = "User $user does not have access to any category in blog $blogid";
		}

	} else {
		$err = $login['err'];
	}

	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1, $err);
	} else {
		// Encode each entry of the array.
		foreach($postlist as $entry) {
			// convert the date
			list($yr,$mo,$da,$ho,$mi)=split("-",$entry['date']);
			$unixtime = mktime($ho,$mi,0,$mo,$da,$yr);
			$isoString=iso8601_encode($unixtime);
			$date = new xmlrpcval($isoString,"dateTime.iso8601");
			$userid = new xmlrpcval($entry['userid']);
			$content = new xmlrpcval($entry['content']);

			$postid = new xmlrpcval($entry['postid']);
			$title = new xmlrpcval($entry['title']);
			$description = new xmlrpcval($entry['description']);
			$link = new xmlrpcval($entry['link']);
			$permalink = new xmlrpcval($entry['permalink']);
			$cat_arr = php_xmlrpc_encode($entry['categories']);

			$encode_arr = array(
				'dateCreated' => $date,
				'userid' => $userid,
				'postid' => $postid,
				'title' => $title,
				'description' => $description,
				'link' => $link,
				'permaLink' => $permalink,
				'categories' => $cat_arr
			);

			$xmlrpcpostarr[] = new xmlrpcval($encode_arr,"struct");
			// $xmlrpcpostarr[] = php_xmlrpc_encode($encode_arr);
		}	
		$myResp = new xmlrpcval($xmlrpcpostarr,"array");
		return new xmlrpcresp($myResp);
	}

}


/**
 * metaWeblog.getCategories
 *
 * @param array $params Contains blog id, username, password
 */
function metaweblog_getCategories ($params) {	
	global $xmlrpcerruser;
	
	$conv = $params->getParam(0); $blogid = $conv->scalarval();
	$conv = $params->getParam(1); $user = $conv->scalarval();
	$conv = $params->getParam(2); $pass = $conv->scalarval();

	// Check password
	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];
	
	if ($uid != -1) {
		$catlist = pivot_get_blog_cats($blogid);
	} else {
		$err = $login['err'];
	}

	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1, $err);
	} else {
		//Make an array of blogs
		foreach($catlist as $entry) {
			$xmlrpccatarr[] = php_xmlrpc_encode($entry);
		}

		// Convert the array to XMLRPC
		$myResp = new xmlrpcval($xmlrpccatarr,"array");

		return new xmlrpcresp($myResp);
	}
}

/**
 * metaWeblog.newMediaObject
 *
 * @param array $params Contains blog id, username, password and file
 */
function metaweblog_newMediaObject ($params) {	
	global $Paths, $xmlrpcerruser;
	
	$conv = $params->getParam(0); $blogid = $conv->scalarval();
	$conv = $params->getParam(1); $user = $conv->scalarval();
	$conv = $params->getParam(2); $pass = $conv->scalarval();
	$conv = $params->getParam(3); $file = php_xmlrpc_decode($conv);

	// Check password
	$login = pivot_get_userid($user,$pass);

	$uid = $login['uid'];
	
	if ($uid != -1) {
		if(!empty($file['name'])) {
			$filename = basename($file['name']);
			$filepath = $Paths['upload_path'].$filename;
			write_file($filepath,$file['bits'],'wb');
		} else {
			debug("Media object has no name.");
			$err = "Media object has no name.";
		}
	} else {
		$err = $login['err'];
	}

	if ($err) {
		return new xmlrpcresp(0, $xmlrpcerruser+1, $err);
	} else {
		// $myResp = new xmlrpcval(array('url'=>$Paths['host'].$Paths['upload_url'].$filename),"array");
		$myResp = php_xmlrpc_encode(array('url'=>$Paths['host'].$Paths['upload_url'].$filename));
		return new xmlrpcresp($myResp);
	}
}


//***********************************************************************************************

//XMLRPC Code


// Set up the server
$s=new xmlrpc_server( 
	array(	"blogger.newPost" =>
			array("function" => "newPost",
				"signature" => array(array($xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcBoolean)),
				"doc" => "Create a new post using the Blogger API"
			),
		"blogger.editPost" =>
			array("function" => "editPost",
				"signature" => array(array($xmlrpcBoolean,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcBoolean)),
				"doc" => "Edit an existing post using the Blogger API"
			),
		"blogger.deletePost" =>
			array("function" => "deletePost",
				"signature" => array(array($xmlrpcBoolean,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcBoolean)),
				"doc" => "Delete an existing post"
			),
		"blogger.getUsersBlogs" =>
			array("function" => "getUsersBlogs",
				"signature" => array(array($xmlrpcArray,$xmlrpcString,$xmlrpcString,$xmlrpcString)),
				"doc" => "Get a list of Pivot categories the user is authorized to access."
			),
		"blogger.getUserInfo" =>
			array("function" => "getUserInf",
				"signature" => array(array($xmlrpcStruct,$xmlrpcString,$xmlrpcString,$xmlrpcString)),
				"doc" => "Get information for a given username"
			),
		"blogger.getTemplate" =>
			array("function" => "getTemplate",
				"signature" => array(array($xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString)),
				"doc" => "We don't support template editing."
			),
		"blogger.setTemplate" =>
			array("function" => "setTemplate",
				"signature" => array(array($xmlrpcBoolean,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString)),
				"doc" => "We don't support template editing."
			),
		"blogger.getPost" =>
			array("function" => "getPost",
				"signature" => array(array($xmlrpcStruct,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString)),
				"doc" => "Get an existing post using the Blogger API"
			),
		"blogger.getRecentPosts" =>
			array("function" => "getRecentPosts",
				"signature" => array(array($xmlrpcArray,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcInt)),
				"doc" => "Get recent posts using the Blogger API"
			),
		"metaWeblog.newPost" =>
			array("function" => "metaweblog_newPost",
				"signature" => array(array($xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcStruct,$xmlrpcBoolean)),
				"doc" => "Create a new post using metaWeblog"
			),
		"metaWeblog.editPost" =>
			array("function" => "metaweblog_editPost",
				"signature" => array(array($xmlrpcBoolean,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcStruct,$xmlrpcBoolean)),
				"doc" => "Edit an existing post using metaWeblog"
			),
		"metaWeblog.getPost" =>
			array("function" => "metaweblog_getPost",
				"signature" => array(array($xmlrpcStruct,$xmlrpcString,$xmlrpcString,$xmlrpcString)),
				"doc" => "Get an existing post using metaWeblog"
			),
		"metaWeblog.getRecentPosts" =>
			array("function" => "metaweblog_getRecentPosts",
				"signature" => array(array($xmlrpcArray,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcInt)),
				"doc" => "Get recent posts using metaWeblog"
			),
		"metaWeblog.getUsersBlogs" =>
			array("function" => "getUsersBlogs",
				"signature" => array(array($xmlrpcArray,$xmlrpcString,$xmlrpcString,$xmlrpcString)),
				"doc" => "Get a list of Pivot weblogs (currently without checking the user permissions)"
			),
		"metaWeblog.getCategories" =>
			array("function" => "metaweblog_getCategories",
				"signature" => array(array($xmlrpcArray,$xmlrpcString,$xmlrpcString,$xmlrpcString)),
				"doc" => "Get a list of Pivot categories"
			),
		"metaWeblog.newMediaObject" =>
			array("function" => "metaweblog_newMediaObject",
				"signature" => array(array($xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcString,$xmlrpcStruct)),
				"doc" => "Uploads a file to your Pivot image directory."
			)
	)
);

?>
