<commit_before><?php
/* To-Do:
 - Automatically detect if incoming data is HTML or BBCode
*/
	require_once("include/bbcode.php");
	require_once("include/datetime.php");
	require_once("include/conversation.php");
	require_once("include/oauth.php");
	require_once("include/html2plain.php");
	/*
	 * Twitter-Like API
	 *
	 */

	$API = Array();
	$called_api = Null;

	function api_user() {
		// It is not sufficient to use local_user() to check whether someone is allowed to use the API,
		// because this will open CSRF holes (just embed an image with src=friendicasite.com/api/statuses/update?status=CSRF
		// into a page, and visitors will post something without noticing it).
		// Instead, use this function.
		if ($_SESSION["allow_api"])
			return local_user();

		return false;
	}

	function api_source() {
		if (requestdata('source'))
			return (requestdata('source'));

		// Support for known clients that doesn't send a source name
		if (strstr($_SERVER['HTTP_USER_AGENT'], "Twidere"))
			return ("Twidere");

		logger("Unrecognized user-agent ".$_SERVER['HTTP_USER_AGENT'], LOGGER_DEBUG);

		return ("api");
	}

	function api_date($str){
		//Wed May 23 06:01:13 +0000 2007
		return datetime_convert('UTC', 'UTC', $str, "D M d H:i:s +0000 Y" );
	}


	function api_register_func($path, $func, $auth=false){
		global $API;
		$API[$path] = array('func'=>$func, 'auth'=>$auth);

		// Workaround for hotot
		$path = str_replace("api/", "api/1.1/", $path);
		$API[$path] = array('func'=>$func, 'auth'=>$auth);
	}

	/**
	 * Simple HTTP Login
	 */

	function api_login(&$a){
		// login with oauth
		try{
			$oauth = new FKOAuth1();
			list($consumer,$token) = $oauth->verify_request(OAuthRequest::from_request());
			if (!is_null($token)){
				$oauth->loginUser($token->uid);
				call_hooks('logged_in', $a->user);
				return;
			}
			echo __file__.__line__.__function__."<pre>"; var_dump($consumer, $token); die();
		}catch(Exception $e){
			logger(__file__.__line__.__function__."\n".$e);
			//die(__file__.__line__.__function__."<pre>".$e); die();
		}



		// workaround for HTTP-auth in CGI mode
		if(x($_SERVER,'REDIRECT_REMOTE_USER')) {
			$userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"],6)) ;
			if(strlen($userpass)) {
				list($name, $password) = explode(':', $userpass);
				$_SERVER['PHP_AUTH_USER'] = $name;
				$_SERVER['PHP_AUTH_PW'] = $password;
			}
		}

		if (!isset($_SERVER['PHP_AUTH_USER'])) {
			logger('API_login: ' . print_r($_SERVER,true), LOGGER_DEBUG);
			header('WWW-Authenticate: Basic realm="Friendica"');
			header('HTTP/1.0 401 Unauthorized');
			die((api_error($a, 'json', "This api requires login")));

			//die('This api requires login');
		}

		$user = $_SERVER['PHP_AUTH_USER'];
		$encrypted = hash('whirlpool',trim($_SERVER['PHP_AUTH_PW']));


		/**
		 *  next code from mod/auth.php. needs better solution
		 */

		// process normal login request

		$r = q("SELECT * FROM `user` WHERE ( `email` = '%s' OR `nickname` = '%s' )
			AND `password` = <PASSWORD>' AND `blocked` = 0 AND `account_expired` = 0 AND `account_removed` = 0 AND `verified` = 1 LIMIT 1",
			dbesc(trim($user)),
			dbesc(trim($user)),
			dbesc($encrypted)
		);
		if(count($r)){
			$record = $r[0];
		} else {
			logger('API_login failure: ' . print_r($_SERVER,true), LOGGER_DEBUG);
			header('WWW-Authenticate: Basic realm="Friendica"');
			header('HTTP/1.0 401 Unauthorized');
			die('This api requires login');
		}

		require_once('include/security.php');
		authenticate_success($record); $_SESSION["allow_api"] = true;

		call_hooks('logged_in', $a->user);

	}

	/**************************
	 *  MAIN API ENTRY POINT  *
	 **************************/
	function api_call(&$a){
		GLOBAL $API, $called_api;

		// preset
		$type="json";
		foreach ($API as $p=>$info){
			if (strpos($a->query_string, $p)===0){
				$called_api= explode("/",$p);
				//unset($_SERVER['PHP_AUTH_USER']);
				if ($info['auth']===true && api_user()===false) {
						api_login($a);
				}

				load_contact_links(api_user());

				logger('API call for ' . $a->user['username'] . ': ' . $a->query_string);
				logger('API parameters: ' . print_r($_REQUEST,true));
				$type="json";
				if (strpos($a->query_string, ".xml")>0) $type="xml";
				if (strpos($a->query_string, ".json")>0) $type="json";
				if (strpos($a->query_string, ".rss")>0) $type="rss";
				if (strpos($a->query_string, ".atom")>0) $type="atom";
				if (strpos($a->query_string, ".as")>0) $type="as";

				$r = call_user_func($info['func'], $a, $type);
				if ($r===false) return;

				switch($type){
					case "xml":
						$r = mb_convert_encoding($r, "UTF-8",mb_detect_encoding($r));
						header ("Content-Type: text/xml");
						return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
						break;
					case "json":
						header ("Content-Type: application/json");
						foreach($r as $rr)
							return json_encode($rr);
						break;
					case "rss":
						header ("Content-Type: application/rss+xml");
						return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
						break;
					case "atom":
						header ("Content-Type: application/atom+xml");
						return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
						break;
					case "as":
						//header ("Content-Type: application/json");
						//foreach($r as $rr)
						//	return json_encode($rr);
						return json_encode($r);
						break;

				}
				//echo "<pre>"; var_dump($r); die();
			}
		}
		header("HTTP/1.1 404 Not Found");
		logger('API call not implemented: '.$a->query_string." - ".print_r($_REQUEST,true));
		return(api_error($a, $type, "not implemented"));

	}

	function api_error(&$a, $type, $error) {
		$r = "<status><error>".$error."</error><request>".$a->query_string."</request></status>";
		switch($type){
			case "xml":
				header ("Content-Type: text/xml");<commit_msg>add jsonp support to api<commit_after><?php
/* To-Do:
 - Automatically detect if incoming data is HTML or BBCode
*/
	require_once("include/bbcode.php");
	require_once("include/datetime.php");
	require_once("include/conversation.php");
	require_once("include/oauth.php");
	require_once("include/html2plain.php");
	/*
	 * Twitter-Like API
	 *
	 */

	$API = Array();
	$called_api = Null;

	function api_user() {
		// It is not sufficient to use local_user() to check whether someone is allowed to use the API,
		// because this will open CSRF holes (just embed an image with src=friendicasite.com/api/statuses/update?status=CSRF
		// into a page, and visitors will post something without noticing it).
		// Instead, use this function.
		if ($_SESSION["allow_api"])
			return local_user();

		return false;
	}

	function api_source() {
		if (requestdata('source'))
			return (requestdata('source'));

		// Support for known clients that doesn't send a source name
		if (strstr($_SERVER['HTTP_USER_AGENT'], "Twidere"))
			return ("Twidere");

		logger("Unrecognized user-agent ".$_SERVER['HTTP_USER_AGENT'], LOGGER_DEBUG);

		return ("api");
	}

	function api_date($str){
		//Wed May 23 06:01:13 +0000 2007
		return datetime_convert('UTC', 'UTC', $str, "D M d H:i:s +0000 Y" );
	}


	function api_register_func($path, $func, $auth=false){
		global $API;
		$API[$path] = array('func'=>$func, 'auth'=>$auth);

		// Workaround for hotot
		$path = str_replace("api/", "api/1.1/", $path);
		$API[$path] = array('func'=>$func, 'auth'=>$auth);
	}

	/**
	 * Simple HTTP Login
	 */

	function api_login(&$a){
		// login with oauth
		try{
			$oauth = new FKOAuth1();
			list($consumer,$token) = $oauth->verify_request(OAuthRequest::from_request());
			if (!is_null($token)){
				$oauth->loginUser($token->uid);
				call_hooks('logged_in', $a->user);
				return;
			}
			echo __file__.__line__.__function__."<pre>"; var_dump($consumer, $token); die();
		}catch(Exception $e){
			logger(__file__.__line__.__function__."\n".$e);
			//die(__file__.__line__.__function__."<pre>".$e); die();
		}



		// workaround for HTTP-auth in CGI mode
		if(x($_SERVER,'REDIRECT_REMOTE_USER')) {
			$userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"],6)) ;
			if(strlen($userpass)) {
				list($name, $password) = explode(':', $userpass);
				$_SERVER['PHP_AUTH_USER'] = $name;
				$_SERVER['PHP_AUTH_PW'] = $password;
			}
		}

		if (!isset($_SERVER['PHP_AUTH_USER'])) {
			logger('API_login: ' . print_r($_SERVER,true), LOGGER_DEBUG);
			header('WWW-Authenticate: Basic realm="Friendica"');
			header('HTTP/1.0 401 Unauthorized');
			die((api_error($a, 'json', "This api requires login")));

			//die('This api requires login');
		}

		$user = $_SERVER['PHP_AUTH_USER'];
		$encrypted = hash('whirlpool',trim($_SERVER['PHP_AUTH_PW']));


		/**
		 *  next code from mod/auth.php. needs better solution
		 */

		// process normal login request

		$r = q("SELECT * FROM `user` WHERE ( `email` = '%s' OR `nickname` = '%s' )
			AND `password` = '%s' AND `blocked` = 0 AND `account_expired` = 0 AND `account_removed` = 0 AND `verified` = 1 LIMIT 1",
			dbesc(trim($user)),
			dbesc(trim($user)),
			dbesc($encrypted)
		);
		if(count($r)){
			$record = $r[0];
		} else {
			logger('API_login failure: ' . print_r($_SERVER,true), LOGGER_DEBUG);
			header('WWW-Authenticate: Basic realm="Friendica"');
			header('HTTP/1.0 401 Unauthorized');
			die('This api requires login');
		}

		require_once('include/security.php');
		authenticate_success($record); $_SESSION["allow_api"] = true;

		call_hooks('logged_in', $a->user);

	}

	/**************************
	 *  MAIN API ENTRY POINT  *
	 **************************/
	function api_call(&$a){
		GLOBAL $API, $called_api;

		// preset
		$type="json";
		foreach ($API as $p=>$info){
			if (strpos($a->query_string, $p)===0){
				$called_api= explode("/",$p);
				//unset($_SERVER['PHP_AUTH_USER']);
				if ($info['auth']===true && api_user()===false) {
						api_login($a);
				}

				load_contact_links(api_user());

				logger('API call for ' . $a->user['username'] . ': ' . $a->query_string);
				logger('API parameters: ' . print_r($_REQUEST,true));
				$type="json";
				if (strpos($a->query_string, ".xml")>0) $type="xml";
				if (strpos($a->query_string, ".json")>0) $type="json";
				if (strpos($a->query_string, ".rss")>0) $type="rss";
				if (strpos($a->query_string, ".atom")>0) $type="atom";
				if (strpos($a->query_string, ".as")>0) $type="as";

				$r = call_user_func($info['func'], $a, $type);
				if ($r===false) return;

				switch($type){
					case "xml":
						$r = mb_convert_encoding($r, "UTF-8",mb_detect_encoding($r));
						header ("Content-Type: text/xml");
						return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
						break;
					case "json":
						header ("Content-Type: application/json");
						foreach($r as $rr)
							$json = json_encode($rr);
							if ($_GET['callback'])
								$json = $_GET['callback']."(".$json.")";
							return $json;							
						break;
					case "rss":
						header ("Content-Type: application/rss+xml");
						return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
						break;
					case "atom":
						header ("Content-Type: application/atom+xml");
						return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
						break;
					case "as":
						//header ("Content-Type: application/json");
						//foreach($r as $rr)
						//	return json_encode($rr);
						return json_encode($r);
						break;

				}
				//echo "<pre>"; var_dump($r); die();
			}
		}
		header("HTTP/1.1 404 Not Found");
		logger('API call not implemented: '.$a->query_string." - ".print_r($_REQUEST,true));
		return(api_error($a, $type, "not implemented"));

	}

	function api_error(&$a, $type, $error) {
		$r = "<status><error>".$error."</error><request>".$a->query_string."</request></status>";
		switch($type){
			case "xml":
				header ("Content-Type: text/xml");
{'fraction_non_alphanumeric': 0.21040531335149865, 'fraction_numerical': 0.010899182561307902, 'mean_word_length': 3.791921664626683, 'pattern_counts': {'":': 12, '<': 30, '<?xml version=': 6, '>': 78, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 22}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1948463', 'n_tokens_mistral': 4886, 'n_tokens_neox': 4095, 'n_words': 861}