Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2619 lines
82 KiB

10 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
  1. <?php
  2. /* To-Do:
  3. - Automatically detect if incoming data is HTML or BBCode
  4. */
  5. require_once("include/bbcode.php");
  6. require_once("include/datetime.php");
  7. require_once("include/conversation.php");
  8. require_once("include/oauth.php");
  9. require_once("include/html2plain.php");
  10. /*
  11. * Twitter-Like API
  12. *
  13. */
  14. $API = Array();
  15. $called_api = Null;
  16. function api_user() {
  17. // It is not sufficient to use local_user() to check whether someone is allowed to use the API,
  18. // because this will open CSRF holes (just embed an image with src=friendicasite.com/api/statuses/update?status=CSRF
  19. // into a page, and visitors will post something without noticing it).
  20. // Instead, use this function.
  21. if ($_SESSION["allow_api"])
  22. return local_user();
  23. return false;
  24. }
  25. function api_date($str){
  26. //Wed May 23 06:01:13 +0000 2007
  27. return datetime_convert('UTC', 'UTC', $str, "D M d H:i:s +0000 Y" );
  28. }
  29. function api_register_func($path, $func, $auth=false){
  30. global $API;
  31. $API[$path] = array('func'=>$func, 'auth'=>$auth);
  32. // Workaround for hotot
  33. $path = str_replace("api/", "api/1.1/", $path);
  34. $API[$path] = array('func'=>$func, 'auth'=>$auth);
  35. }
  36. /**
  37. * Simple HTTP Login
  38. */
  39. function api_login(&$a){
  40. // login with oauth
  41. try{
  42. $oauth = new FKOAuth1();
  43. list($consumer,$token) = $oauth->verify_request(OAuthRequest::from_request());
  44. if (!is_null($token)){
  45. $oauth->loginUser($token->uid);
  46. call_hooks('logged_in', $a->user);
  47. return;
  48. }
  49. echo __file__.__line__.__function__."<pre>"; var_dump($consumer, $token); die();
  50. }catch(Exception $e){
  51. logger(__file__.__line__.__function__."\n".$e);
  52. //die(__file__.__line__.__function__."<pre>".$e); die();
  53. }
  54. // workaround for HTTP-auth in CGI mode
  55. if(x($_SERVER,'REDIRECT_REMOTE_USER')) {
  56. $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"],6)) ;
  57. if(strlen($userpass)) {
  58. list($name, $password) = explode(':', $userpass);
  59. $_SERVER['PHP_AUTH_USER'] = $name;
  60. $_SERVER['PHP_AUTH_PW'] = $password;
  61. }
  62. }
  63. if (!isset($_SERVER['PHP_AUTH_USER'])) {
  64. logger('API_login: ' . print_r($_SERVER,true), LOGGER_DEBUG);
  65. header('WWW-Authenticate: Basic realm="Friendica"');
  66. header('HTTP/1.0 401 Unauthorized');
  67. die((api_error($a, 'json', "This api requires login")));
  68. //die('This api requires login');
  69. }
  70. $user = $_SERVER['PHP_AUTH_USER'];
  71. $encrypted = hash('whirlpool',trim($_SERVER['PHP_AUTH_PW']));
  72. /**
  73. * next code from mod/auth.php. needs better solution
  74. */
  75. // process normal login request
  76. $r = q("SELECT * FROM `user` WHERE ( `email` = '%s' OR `nickname` = '%s' )
  77. AND `password` = '%s' AND `blocked` = 0 AND `account_expired` = 0 AND `account_removed` = 0 AND `verified` = 1 LIMIT 1",
  78. dbesc(trim($user)),
  79. dbesc(trim($user)),
  80. dbesc($encrypted)
  81. );
  82. if(count($r)){
  83. $record = $r[0];
  84. } else {
  85. logger('API_login failure: ' . print_r($_SERVER,true), LOGGER_DEBUG);
  86. header('WWW-Authenticate: Basic realm="Friendica"');
  87. header('HTTP/1.0 401 Unauthorized');
  88. die('This api requires login');
  89. }
  90. require_once('include/security.php');
  91. authenticate_success($record); $_SESSION["allow_api"] = true;
  92. call_hooks('logged_in', $a->user);
  93. }
  94. /**************************
  95. * MAIN API ENTRY POINT *
  96. **************************/
  97. function api_call(&$a){
  98. GLOBAL $API, $called_api;
  99. // preset
  100. $type="json";
  101. foreach ($API as $p=>$info){
  102. if (strpos($a->query_string, $p)===0){
  103. $called_api= explode("/",$p);
  104. //unset($_SERVER['PHP_AUTH_USER']);
  105. if ($info['auth']===true && api_user()===false) {
  106. api_login($a);
  107. }
  108. load_contact_links(api_user());
  109. logger('API call for ' . $a->user['username'] . ': ' . $a->query_string);
  110. logger('API parameters: ' . print_r($_REQUEST,true));
  111. $type="json";
  112. if (strpos($a->query_string, ".xml")>0) $type="xml";
  113. if (strpos($a->query_string, ".json")>0) $type="json";
  114. if (strpos($a->query_string, ".rss")>0) $type="rss";
  115. if (strpos($a->query_string, ".atom")>0) $type="atom";
  116. if (strpos($a->query_string, ".as")>0) $type="as";
  117. $r = call_user_func($info['func'], $a, $type);
  118. if ($r===false) return;
  119. switch($type){
  120. case "xml":
  121. $r = mb_convert_encoding($r, "UTF-8",mb_detect_encoding($r));
  122. header ("Content-Type: text/xml");
  123. return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
  124. break;
  125. case "json":
  126. header ("Content-Type: application/json");
  127. foreach($r as $rr)
  128. return json_encode($rr);
  129. break;
  130. case "rss":
  131. header ("Content-Type: application/rss+xml");
  132. return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
  133. break;
  134. case "atom":
  135. header ("Content-Type: application/atom+xml");
  136. return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
  137. break;
  138. case "as":
  139. //header ("Content-Type: application/json");
  140. //foreach($r as $rr)
  141. // return json_encode($rr);
  142. return json_encode($r);
  143. break;
  144. }
  145. //echo "<pre>"; var_dump($r); die();
  146. }
  147. }
  148. header("HTTP/1.1 404 Not Found");
  149. logger('API call not implemented: '.$a->query_string." - ".print_r($_REQUEST,true));
  150. return(api_error($a, $type, "not implemented"));
  151. }
  152. function api_error(&$a, $type, $error) {
  153. $r = "<status><error>".$error."</error><request>".$a->query_string."</request></status>";
  154. switch($type){
  155. case "xml":
  156. header ("Content-Type: text/xml");
  157. return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
  158. break;
  159. case "json":
  160. header ("Content-Type: application/json");
  161. return json_encode(array('error' => $error, 'request' => $a->query_string));
  162. break;
  163. case "rss":
  164. header ("Content-Type: application/rss+xml");
  165. return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
  166. break;
  167. case "atom":
  168. header ("Content-Type: application/atom+xml");
  169. return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
  170. break;
  171. }
  172. }
  173. /**
  174. * RSS extra info
  175. */
  176. function api_rss_extra(&$a, $arr, $user_info){
  177. if (is_null($user_info)) $user_info = api_get_user($a);
  178. $arr['$user'] = $user_info;
  179. $arr['$rss'] = array(
  180. 'alternate' => $user_info['url'],
  181. 'self' => $a->get_baseurl(). "/". $a->query_string,
  182. 'base' => $a->get_baseurl(),
  183. 'updated' => api_date(null),
  184. 'atom_updated' => datetime_convert('UTC','UTC','now',ATOM_TIME),
  185. 'language' => $user_info['language'],
  186. 'logo' => $a->get_baseurl()."/images/friendica-32.png",
  187. );
  188. return $arr;
  189. }
  190. /**
  191. * Unique contact to contact url.
  192. */
  193. function api_unique_id_to_url($id){
  194. $r = q("SELECT url FROM unique_contacts WHERE id=%d LIMIT 1",
  195. intval($id));
  196. if ($r)
  197. return ($r[0]["url"]);
  198. else
  199. return false;
  200. }
  201. /**
  202. * Returns user info array.
  203. */
  204. function api_get_user(&$a, $contact_id = Null, $type = "json"){
  205. global $called_api;
  206. $user = null;
  207. $extra_query = "";
  208. $url = "";
  209. $nick = "";
  210. logger("api_get_user: Fetching user data for user ".$contact_id, LOGGER_DEBUG);
  211. // Searching for contact URL
  212. if(!is_null($contact_id) AND (intval($contact_id) == 0)){
  213. $user = dbesc(normalise_link($contact_id));
  214. $url = $user;
  215. $extra_query = "AND `contact`.`nurl` = '%s' ";
  216. if (api_user()!==false) $extra_query .= "AND `contact`.`uid`=".intval(api_user());
  217. }
  218. // Searching for unique contact id
  219. if(!is_null($contact_id) AND (intval($contact_id) != 0)){
  220. $user = dbesc(api_unique_id_to_url($contact_id));
  221. if ($user == "")
  222. die(api_error($a, $type, t("User not found.")));
  223. $url = $user;
  224. $extra_query = "AND `contact`.`nurl` = '%s' ";
  225. if (api_user()!==false) $extra_query .= "AND `contact`.`uid`=".intval(api_user());
  226. }
  227. if(is_null($user) && x($_GET, 'user_id')) {
  228. $user = dbesc(api_unique_id_to_url($_GET['user_id']));
  229. if ($user == "")
  230. die(api_error($a, $type, t("User not found.")));
  231. $url = $user;
  232. $extra_query = "AND `contact`.`nurl` = '%s' ";
  233. if (api_user()!==false) $extra_query .= "AND `contact`.`uid`=".intval(api_user());
  234. }
  235. if(is_null($user) && x($_GET, 'screen_name')) {
  236. $user = dbesc($_GET['screen_name']);
  237. $nick = $user;
  238. $extra_query = "AND `contact`.`nick` = '%s' ";
  239. if (api_user()!==false) $extra_query .= "AND `contact`.`uid`=".intval(api_user());
  240. }
  241. if (is_null($user) AND ($a->argc > (count($called_api)-1)) AND (count($called_api) > 0)){
  242. $argid = count($called_api);
  243. list($user, $null) = explode(".",$a->argv[$argid]);
  244. if(is_numeric($user)){
  245. $user = dbesc(api_unique_id_to_url($user));
  246. if ($user == "")
  247. return false;
  248. $url = $user;
  249. $extra_query = "AND `contact`.`nurl` = '%s' ";
  250. if (api_user()!==false) $extra_query .= "AND `contact`.`uid`=".intval(api_user());
  251. } else {
  252. $user = dbesc($user);
  253. $nick = $user;
  254. $extra_query = "AND `contact`.`nick` = '%s' ";
  255. if (api_user()!==false) $extra_query .= "AND `contact`.`uid`=".intval(api_user());
  256. }
  257. }
  258. logger("api_get_user: user ".$user, LOGGER_DEBUG);
  259. if (!$user) {
  260. if (api_user()===false) {
  261. api_login($a); return False;
  262. } else {
  263. $user = $_SESSION['uid'];
  264. $extra_query = "AND `contact`.`uid` = %d AND `contact`.`self` = 1 ";
  265. }
  266. }
  267. logger('api_user: ' . $extra_query . ', user: ' . $user);
  268. // user info
  269. $uinfo = q("SELECT *, `contact`.`id` as `cid` FROM `contact`
  270. WHERE 1
  271. $extra_query",
  272. $user
  273. );
  274. // Selecting the id by priority, friendica first
  275. api_best_nickname($uinfo);
  276. // if the contact wasn't found, fetch it from the unique contacts
  277. if (count($uinfo)==0) {
  278. $r = array();
  279. if ($url != "")
  280. $r = q("SELECT * FROM unique_contacts WHERE url='%s' LIMIT 1", $url);
  281. elseif ($nick != "")
  282. $r = q("SELECT * FROM unique_contacts WHERE nick='%s' LIMIT 1", $nick);
  283. if ($r) {
  284. // If no nick where given, extract it from the address
  285. if (($r[0]['nick'] == "") OR ($r[0]['name'] == $r[0]['nick']))
  286. $r[0]['nick'] = api_get_nick($r[0]["url"]);
  287. $ret = array(
  288. 'id' => $r[0]["id"],
  289. 'id_str' => (string) $r[0]["id"],
  290. 'name' => $r[0]["name"],
  291. 'screen_name' => (($r[0]['nick']) ? $r[0]['nick'] : $r[0]['name']),
  292. 'location' => NULL,
  293. 'description' => NULL,
  294. 'profile_image_url' => $r[0]["avatar"],
  295. 'profile_image_url_https' => $r[0]["avatar"],
  296. 'url' => $r[0]["url"],
  297. 'protected' => false,
  298. 'followers_count' => 0,
  299. 'friends_count' => 0,
  300. 'created_at' => api_date(0),
  301. 'favourites_count' => 0,
  302. 'utc_offset' => 0,
  303. 'time_zone' => 'UTC',
  304. 'statuses_count' => 0,
  305. 'following' => false,
  306. 'verified' => false,
  307. 'statusnet_blocking' => false,
  308. 'notifications' => false,
  309. 'statusnet_profile_url' => $r[0]["url"],
  310. 'uid' => 0,
  311. 'cid' => 0,
  312. 'self' => 0,
  313. 'network' => '',
  314. );
  315. return $ret;
  316. } else
  317. die(api_error($a, $type, t("User not found.")));
  318. }
  319. if($uinfo[0]['self']) {
  320. $usr = q("select * from user where uid = %d limit 1",
  321. intval(api_user())
  322. );
  323. $profile = q("select * from profile where uid = %d and `is-default` = 1 limit 1",
  324. intval(api_user())
  325. );
  326. //AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''",
  327. // count public wall messages
  328. $r = q("SELECT count(*) as `count` FROM `item`
  329. WHERE `uid` = %d
  330. AND `type`='wall'",
  331. intval($uinfo[0]['uid'])
  332. );
  333. $countitms = $r[0]['count'];
  334. }
  335. else {
  336. //AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''",
  337. $r = q("SELECT count(*) as `count` FROM `item`
  338. WHERE `contact-id` = %d",
  339. intval($uinfo[0]['id'])
  340. );
  341. $countitms = $r[0]['count'];
  342. }
  343. // count friends
  344. $r = q("SELECT count(*) as `count` FROM `contact`
  345. WHERE `uid` = %d AND `rel` IN ( %d, %d )
  346. AND `self`=0 AND `blocked`=0 AND `pending`=0 AND `hidden`=0",
  347. intval($uinfo[0]['uid']),
  348. intval(CONTACT_IS_SHARING),
  349. intval(CONTACT_IS_FRIEND)
  350. );
  351. $countfriends = $r[0]['count'];
  352. $r = q("SELECT count(*) as `count` FROM `contact`
  353. WHERE `uid` = %d AND `rel` IN ( %d, %d )
  354. AND `self`=0 AND `blocked`=0 AND `pending`=0 AND `hidden`=0",
  355. intval($uinfo[0]['uid']),
  356. intval(CONTACT_IS_FOLLOWER),
  357. intval(CONTACT_IS_FRIEND)
  358. );
  359. $countfollowers = $r[0]['count'];
  360. $r = q("SELECT count(*) as `count` FROM item where starred = 1 and uid = %d and deleted = 0",
  361. intval($uinfo[0]['uid'])
  362. );
  363. $starred = $r[0]['count'];
  364. if(! $uinfo[0]['self']) {
  365. $countfriends = 0;
  366. $countfollowers = 0;
  367. $starred = 0;
  368. }
  369. // Add a nick if it isn't present there
  370. if (($uinfo[0]['nick'] == "") OR ($uinfo[0]['name'] == $uinfo[0]['nick'])) {
  371. $uinfo[0]['nick'] = api_get_nick($uinfo[0]["url"]);
  372. }
  373. // Fetching unique id
  374. $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1", dbesc(normalise_link($uinfo[0]['url'])));
  375. // If not there, then add it
  376. if (count($r) == 0) {
  377. q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
  378. dbesc(normalise_link($uinfo[0]['url'])), dbesc($uinfo[0]['name']),dbesc($uinfo[0]['nick']), dbesc($uinfo[0]['micro']));
  379. $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1", dbesc(normalise_link($uinfo[0]['url'])));
  380. }
  381. require_once('include/contact_selectors.php');
  382. $network_name = network_to_name($uinfo[0]['network']);
  383. $ret = Array(
  384. 'id' => intval($r[0]['id']),
  385. 'id_str' => (string) intval($r[0]['id']),
  386. 'name' => (($uinfo[0]['name']) ? $uinfo[0]['name'] : $uinfo[0]['nick']),
  387. 'screen_name' => (($uinfo[0]['nick']) ? $uinfo[0]['nick'] : $uinfo[0]['name']),
  388. 'location' => ($usr) ? $usr[0]['default-location'] : $network_name,
  389. 'description' => (($profile) ? $profile[0]['pdesc'] : NULL),
  390. 'profile_image_url' => $uinfo[0]['micro'],
  391. 'profile_image_url_https' => $uinfo[0]['micro'],
  392. 'url' => $uinfo[0]['url'],
  393. 'protected' => false,
  394. 'followers_count' => intval($countfollowers),
  395. 'friends_count' => intval($countfriends),
  396. 'created_at' => api_date($uinfo[0]['created']),
  397. 'favourites_count' => intval($starred),
  398. 'utc_offset' => "0",
  399. 'time_zone' => 'UTC',
  400. 'statuses_count' => intval($countitms),
  401. 'following' => (($uinfo[0]['rel'] == CONTACT_IS_FOLLOWER) OR ($uinfo[0]['rel'] == CONTACT_IS_FRIEND)),
  402. 'verified' => true,
  403. 'statusnet_blocking' => false,
  404. 'notifications' => false,
  405. 'statusnet_profile_url' => $a->get_baseurl()."/contacts/".$uinfo[0]['cid'],
  406. 'uid' => intval($uinfo[0]['uid']),
  407. 'cid' => intval($uinfo[0]['cid']),
  408. 'self' => $uinfo[0]['self'],
  409. 'network' => $uinfo[0]['network'],
  410. );
  411. return $ret;
  412. }
  413. function api_item_get_user(&$a, $item) {
  414. $author = q("SELECT * FROM unique_contacts WHERE url='%s' LIMIT 1",
  415. dbesc(normalise_link($item['author-link'])));
  416. if (count($author) == 0) {
  417. q("INSERT INTO unique_contacts (url, name, avatar) VALUES ('%s', '%s', '%s')",
  418. dbesc(normalise_link($item["author-link"])), dbesc($item["author-name"]), dbesc($item["author-avatar"]));
  419. $author = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
  420. dbesc(normalise_link($item['author-link'])));
  421. } else if ($item["author-link"].$item["author-name"] != $author[0]["url"].$author[0]["name"]) {
  422. q("UPDATE unique_contacts SET name = '%s', avatar = '%s' WHERE url = '%s'",
  423. dbesc($item["author-name"]), dbesc($item["author-avatar"]), dbesc(normalise_link($item["author-link"])));
  424. }
  425. $owner = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
  426. dbesc(normalise_link($item['owner-link'])));
  427. if (count($owner) == 0) {
  428. q("INSERT INTO unique_contacts (url, name, avatar) VALUES ('%s', '%s', '%s')",
  429. dbesc(normalise_link($item["owner-link"])), dbesc($item["owner-name"]), dbesc($item["owner-avatar"]));
  430. $owner = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
  431. dbesc(normalise_link($item['owner-link'])));
  432. } else if ($item["owner-link"].$item["owner-name"] != $owner[0]["url"].$owner[0]["name"]) {
  433. q("UPDATE unique_contacts SET name = '%s', avatar = '%s' WHERE url = '%s'",
  434. dbesc($item["owner-name"]), dbesc($item["owner-avatar"]), dbesc(normalise_link($item["owner-link"])));
  435. }
  436. // Comments in threads may appear as wall-to-wall postings.
  437. // So only take the owner at the top posting.
  438. if ($item["id"] == $item["parent"])
  439. $status_user = api_get_user($a,$item["owner-link"]);
  440. else
  441. $status_user = api_get_user($a,$item["author-link"]);
  442. $status_user["protected"] = (($item["allow_cid"] != "") OR
  443. ($item["allow_gid"] != "") OR
  444. ($item["deny_cid"] != "") OR
  445. ($item["deny_gid"] != "") OR
  446. $item["private"]);
  447. return ($status_user);
  448. }
  449. /**
  450. * load api $templatename for $type and replace $data array
  451. */
  452. function api_apply_template($templatename, $type, $data){
  453. $a = get_app();
  454. switch($type){
  455. case "atom":
  456. case "rss":
  457. case "xml":
  458. $data = array_xmlify($data);
  459. $tpl = get_markup_template("api_".$templatename."_".$type.".tpl");
  460. if(! $tpl) {
  461. header ("Content-Type: text/xml");
  462. echo '<?xml version="1.0" encoding="UTF-8"?>'."\n".'<status><error>not implemented</error></status>';
  463. killme();
  464. }
  465. $ret = replace_macros($tpl, $data);
  466. break;
  467. case "json":
  468. $ret = $data;
  469. break;
  470. }
  471. return $ret;
  472. }
  473. /**
  474. ** TWITTER API
  475. */
  476. /**
  477. * Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful;
  478. * returns a 401 status code and an error message if not.
  479. * http://developer.twitter.com/doc/get/account/verify_credentials
  480. */
  481. function api_account_verify_credentials(&$a, $type){
  482. if (api_user()===false) return false;
  483. unset($_REQUEST["user_id"]);
  484. unset($_GET["user_id"]);
  485. unset($_REQUEST["screen_name"]);
  486. unset($_GET["screen_name"]);
  487. $skip_status = (x($_REQUEST,'skip_status')?$_REQUEST['skip_status']:false);
  488. $user_info = api_get_user($a);
  489. // "verified" isn't used here in the standard
  490. unset($user_info["verified"]);
  491. // - Adding last status
  492. if (!$skip_status) {
  493. $user_info["status"] = api_status_show($a,"raw");
  494. if (!count($user_info["status"]))
  495. unset($user_info["status"]);
  496. else
  497. unset($user_info["status"]["user"]);
  498. }
  499. // "uid" and "self" are only needed for some internal stuff, so remove it from here
  500. unset($user_info["uid"]);
  501. unset($user_info["self"]);
  502. return api_apply_template("user", $type, array('$user' => $user_info));
  503. }
  504. api_register_func('api/account/verify_credentials','api_account_verify_credentials', true);
  505. /**
  506. * get data from $_POST or $_GET
  507. */
  508. function requestdata($k){
  509. if (isset($_POST[$k])){
  510. return $_POST[$k];
  511. }
  512. if (isset($_GET[$k])){
  513. return $_GET[$k];
  514. }
  515. return null;
  516. }
  517. /*Waitman Gobble Mod*/
  518. function api_statuses_mediap(&$a, $type) {
  519. if (api_user()===false) {
  520. logger('api_statuses_update: no user');
  521. return false;
  522. }
  523. $user_info = api_get_user($a);
  524. $_REQUEST['type'] = 'wall';
  525. $_REQUEST['profile_uid'] = api_user();
  526. $_REQUEST['api_source'] = true;
  527. $txt = requestdata('status');
  528. //$txt = urldecode(requestdata('status'));
  529. require_once('library/HTMLPurifier.auto.php');
  530. require_once('include/html2bbcode.php');
  531. if((strpos($txt,'<') !== false) || (strpos($txt,'>') !== false)) {
  532. $txt = html2bb_video($txt);
  533. $config = HTMLPurifier_Config::createDefault();
  534. $config->set('Cache.DefinitionImpl', null);
  535. $purifier = new HTMLPurifier($config);
  536. $txt = $purifier->purify($txt);
  537. }
  538. $txt = html2bbcode($txt);
  539. $a->argv[1]=$user_info['screen_name']; //should be set to username?
  540. $_REQUEST['hush']='yeah'; //tell wall_upload function to return img info instead of echo
  541. require_once('mod/wall_upload.php');
  542. $bebop = wall_upload_post($a);
  543. //now that we have the img url in bbcode we can add it to the status and insert the wall item.
  544. $_REQUEST['body']=$txt."\n\n".$bebop;
  545. require_once('mod/item.php');
  546. item_post($a);
  547. // this should output the last post (the one we just posted).
  548. return api_status_show($a,$type);
  549. }
  550. api_register_func('api/statuses/mediap','api_statuses_mediap', true);
  551. /*Waitman Gobble Mod*/
  552. function api_statuses_update(&$a, $type) {
  553. if (api_user()===false) {
  554. logger('api_statuses_update: no user');
  555. return false;
  556. }
  557. $user_info = api_get_user($a);
  558. // convert $_POST array items to the form we use for web posts.
  559. // logger('api_post: ' . print_r($_POST,true));
  560. if(requestdata('htmlstatus')) {
  561. require_once('library/HTMLPurifier.auto.php');
  562. require_once('include/html2bbcode.php');
  563. $txt = requestdata('htmlstatus');
  564. if((strpos($txt,'<') !== false) || (strpos($txt,'>') !== false)) {
  565. $txt = html2bb_video($txt);
  566. $config = HTMLPurifier_Config::createDefault();
  567. $config->set('Cache.DefinitionImpl', null);
  568. $purifier = new HTMLPurifier($config);
  569. $txt = $purifier->purify($txt);
  570. $_REQUEST['body'] = html2bbcode($txt);
  571. }
  572. }
  573. else
  574. $_REQUEST['body'] = requestdata('status');
  575. $_REQUEST['title'] = requestdata('title');
  576. $parent = requestdata('in_reply_to_status_id');
  577. if(ctype_digit($parent))
  578. $_REQUEST['parent'] = $parent;
  579. else
  580. $_REQUEST['parent_uri'] = $parent;
  581. if(requestdata('lat') && requestdata('long'))
  582. $_REQUEST['coord'] = sprintf("%s %s",requestdata('lat'),requestdata('long'));
  583. $_REQUEST['profile_uid'] = api_user();
  584. if($parent)
  585. $_REQUEST['type'] = 'net-comment';
  586. else {
  587. // logger("api_statuses_update: upload ".print_r($_FILES, true)." ".print_r($_POST, true)." ".print_r($_GET, true), LOGGER_DEBUG);
  588. //die("blubb");
  589. $_REQUEST['type'] = 'wall';
  590. if(x($_FILES,'media')) {
  591. // upload the image if we have one
  592. $_REQUEST['hush']='yeah'; //tell wall_upload function to return img info instead of echo
  593. require_once('mod/wall_upload.php');
  594. $media = wall_upload_post($a);
  595. if(strlen($media)>0)
  596. $_REQUEST['body'] .= "\n\n".$media;
  597. }
  598. }
  599. // set this so that the item_post() function is quiet and doesn't redirect or emit json
  600. $_REQUEST['api_source'] = true;
  601. // call out normal post function
  602. require_once('mod/item.php');
  603. item_post($a);
  604. // this should output the last post (the one we just posted).
  605. return api_status_show($a,$type);
  606. }
  607. api_register_func('api/statuses/update','api_statuses_update', true);
  608. api_register_func('api/statuses/update_with_media','api_statuses_update', true);
  609. function api_status_show(&$a, $type){
  610. $user_info = api_get_user($a);
  611. logger('api_status_show: user_info: '.print_r($user_info, true), LOGGER_DEBUG);
  612. // get last public wall message
  613. $lastwall = q("SELECT `item`.*, `i`.`contact-id` as `reply_uid`, `i`.`author-link` AS `item-author`
  614. FROM `item`, `item` as `i`
  615. WHERE `item`.`contact-id` = %d
  616. AND ((`item`.`author-link` IN ('%s', '%s')) OR (`item`.`owner-link` IN ('%s', '%s')))
  617. AND `i`.`id` = `item`.`parent`
  618. AND `item`.`type`!='activity'
  619. AND `item`.`allow_cid`='' AND `item`.`allow_gid`='' AND `item`.`deny_cid`='' AND `item`.`deny_gid`=''
  620. ORDER BY `item`.`created` DESC
  621. LIMIT 1",
  622. intval($user_info['cid']),
  623. dbesc($user_info['url']),
  624. dbesc(normalise_link($user_info['url'])),
  625. dbesc($user_info['url']),
  626. dbesc(normalise_link($user_info['url']))
  627. );
  628. if (count($lastwall)>0){
  629. $lastwall = $lastwall[0];
  630. $in_reply_to_status_id = NULL;
  631. $in_reply_to_user_id = NULL;
  632. $in_reply_to_status_id_str = NULL;
  633. $in_reply_to_user_id_str = NULL;
  634. $in_reply_to_screen_name = NULL;
  635. if (intval($lastwall['parent']) != intval($lastwall['id'])) {
  636. $in_reply_to_status_id= intval($lastwall['parent']);
  637. $in_reply_to_status_id_str = (string) intval($lastwall['parent']);
  638. $r = q("SELECT * FROM unique_contacts WHERE `url` = '%s'", dbesc(normalise_link($lastwall['item-author'])));
  639. if ($r) {
  640. if ($r[0]['nick'] == "")
  641. $r[0]['nick'] = api_get_nick($r[0]["url"]);
  642. $in_reply_to_screen_name = (($r[0]['nick']) ? $r[0]['nick'] : $r[0]['name']);
  643. $in_reply_to_user_id = intval($r[0]['id']);
  644. $in_reply_to_user_id_str = (string) intval($r[0]['id']);
  645. }
  646. }
  647. // There seems to be situation, where both fields are identical:
  648. // https://github.com/friendica/friendica/issues/1010
  649. // This is a bugfix for that.
  650. if (intval($in_reply_to_status_id) == intval($lastwall['id'])) {
  651. logger('api_status_show: this message should never appear: id: '.$lastwall['id'].' similar to reply-to: '.$in_reply_to_status_id, LOGGER_DEBUG);
  652. $in_reply_to_status_id = NULL;
  653. $in_reply_to_user_id = NULL;
  654. $in_reply_to_status_id_str = NULL;
  655. $in_reply_to_user_id_str = NULL;
  656. $in_reply_to_screen_name = NULL;
  657. }
  658. $status_info = array(
  659. 'text' => trim(html2plain(bbcode(api_clean_plain_items($lastwall['body']), false, false, 2, true), 0)),
  660. 'truncated' => false,
  661. 'created_at' => api_date($lastwall['created']),
  662. 'in_reply_to_status_id' => $in_reply_to_status_id,
  663. 'in_reply_to_status_id_str' => $in_reply_to_status_id_str,
  664. 'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
  665. 'id' => intval($lastwall['id']),
  666. 'id_str' => (string) $lastwall['id'],
  667. 'in_reply_to_user_id' => $in_reply_to_user_id,
  668. 'in_reply_to_user_id_str' => $in_reply_to_user_id_str,
  669. 'in_reply_to_screen_name' => $in_reply_to_screen_name,
  670. 'geo' => NULL,
  671. 'favorited' => false,
  672. // attachments
  673. 'user' => $user_info,
  674. 'statusnet_html' => trim(bbcode($lastwall['body'], false, false)),
  675. 'statusnet_conversation_id' => $lastwall['parent'],
  676. );
  677. if ($lastwall['title'] != "")
  678. $status_info['statusnet_html'] = "<h4>".bbcode($lastwall['title'])."</h4>\n".$status_info['statusnet_html'];
  679. $entities = api_get_entitities($status_info['text'], $lastwall['body']);
  680. if (count($entities) > 0)
  681. $status_info['entities'] = $entities;
  682. if (($lastwall['item_network'] != "") AND ($status["source"] == 'web'))
  683. $status_info["source"] = network_to_name($lastwall['item_network']);
  684. elseif (($lastwall['item_network'] != "") AND (network_to_name($lastwall['item_network']) != $status_info["source"]))
  685. $status_info["source"] = trim($status_info["source"].' ('.network_to_name($lastwall['item_network']).')');
  686. // "uid" and "self" are only needed for some internal stuff, so remove it from here
  687. unset($status_info["user"]["uid"]);
  688. unset($status_info["user"]["self"]);
  689. }
  690. if ($type == "raw")
  691. return($status_info);
  692. return api_apply_template("status", $type, array('$status' => $status_info));
  693. }
  694. /**
  695. * Returns extended information of a given user, specified by ID or screen name as per the required id parameter.
  696. * The author's most recent status will be returned inline.
  697. * http://developer.twitter.com/doc/get/users/show
  698. */
  699. function api_users_show(&$a, $type){
  700. $user_info = api_get_user($a);
  701. $lastwall = q("SELECT `item`.*
  702. FROM `item`, `contact`
  703. WHERE `item`.`uid` = %d AND `verb` = '%s' AND `item`.`contact-id` = %d
  704. AND ((`item`.`author-link` IN ('%s', '%s')) OR (`item`.`owner-link` IN ('%s', '%s')))
  705. AND `contact`.`id`=`item`.`contact-id`
  706. AND `type`!='activity'
  707. AND `item`.`allow_cid`='' AND `item`.`allow_gid`='' AND `item`.`deny_cid`='' AND `item`.`deny_gid`=''
  708. ORDER BY `created` DESC
  709. LIMIT 1",
  710. intval(api_user()),
  711. dbesc(ACTIVITY_POST),
  712. intval($user_info['cid']),
  713. dbesc($user_info['url']),
  714. dbesc(normalise_link($user_info['url'])),
  715. dbesc($user_info['url']),
  716. dbesc(normalise_link($user_info['url']))
  717. );
  718. if (count($lastwall)>0){
  719. $lastwall = $lastwall[0];
  720. $in_reply_to_status_id = NULL;
  721. $in_reply_to_user_id = NULL;
  722. $in_reply_to_status_id_str = NULL;
  723. $in_reply_to_user_id_str = NULL;
  724. $in_reply_to_screen_name = NULL;
  725. if ($lastwall['parent']!=$lastwall['id']) {
  726. $reply = q("SELECT `item`.`id`, `item`.`contact-id` as `reply_uid`, `contact`.`nick` as `reply_author`, `item`.`author-link` AS `item-author`
  727. FROM `item`,`contact` WHERE `contact`.`id`=`item`.`contact-id` AND `item`.`id` = %d", intval($lastwall['parent']));
  728. if (count($reply)>0) {
  729. $in_reply_to_status_id = intval($lastwall['parent']);
  730. $in_reply_to_status_id_str = (string) intval($lastwall['parent']);
  731. $r = q("SELECT * FROM unique_contacts WHERE `url` = '%s'", dbesc(normalise_link($reply[0]['item-author'])));
  732. if ($r) {
  733. if ($r[0]['nick'] == "")
  734. $r[0]['nick'] = api_get_nick($r[0]["url"]);
  735. $in_reply_to_screen_name = (($r[0]['nick']) ? $r[0]['nick'] : $r[0]['name']);
  736. $in_reply_to_user_id = intval($r[0]['id']);
  737. $in_reply_to_user_id_str = (string) intval($r[0]['id']);
  738. }
  739. }
  740. }
  741. $user_info['status'] = array(
  742. 'text' => trim(html2plain(bbcode(api_clean_plain_items($lastwall['body']), false, false, 2, true), 0)),
  743. 'truncated' => false,
  744. 'created_at' => api_date($lastwall['created']),
  745. 'in_reply_to_status_id' => $in_reply_to_status_id,
  746. 'in_reply_to_status_id_str' => $in_reply_to_status_id_str,
  747. 'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
  748. 'id' => intval($lastwall['contact-id']),
  749. 'id_str' => (string) $lastwall['contact-id'],
  750. 'in_reply_to_user_id' => $in_reply_to_user_id,
  751. 'in_reply_to_user_id_str' => $in_reply_to_user_id_str,
  752. 'in_reply_to_screen_name' => $in_reply_to_screen_name,
  753. 'geo' => NULL,
  754. 'favorited' => false,
  755. 'statusnet_html' => trim(bbcode($lastwall['body'], false, false)),
  756. 'statusnet_conversation_id' => $lastwall['parent'],
  757. );
  758. if ($lastwall['title'] != "")
  759. $user_info['statusnet_html'] = "<h4>".bbcode($lastwall['title'])."</h4>\n".$user_info['statusnet_html'];
  760. $entities = api_get_entitities($user_info['text'], $lastwall['body']);
  761. if (count($entities) > 0)
  762. $user_info['entities'] = $entities;
  763. if (($lastwall['item_network'] != "") AND ($user_info["status"]["source"] == 'web'))
  764. $user_info["status"]["source"] = network_to_name($lastwall['item_network']);
  765. if (($lastwall['item_network'] != "") AND (network_to_name($lastwall['item_network']) != $user_info["status"]["source"]))
  766. $user_info["status"]["source"] = trim($user_info["status"]["source"].' ('.network_to_name($lastwall['item_network']).')');
  767. }
  768. // "uid" and "self" are only needed for some internal stuff, so remove it from here
  769. unset($user_info["uid"]);
  770. unset($user_info["self"]);
  771. return api_apply_template("user", $type, array('$user' => $user_info));
  772. }
  773. api_register_func('api/users/show','api_users_show');
  774. function api_users_search(&$a, $type) {
  775. $page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
  776. $userlist = array();
  777. if (isset($_GET["q"])) {
  778. $r = q("SELECT id FROM unique_contacts WHERE name='%s'", dbesc($_GET["q"]));
  779. if (!count($r))
  780. $r = q("SELECT id FROM unique_contacts WHERE nick='%s'", dbesc($_GET["q"]));
  781. if (count($r)) {
  782. foreach ($r AS $user) {
  783. $user_info = api_get_user($a, $user["id"]);
  784. //echo print_r($user_info, true)."\n";
  785. $userdata = api_apply_template("user", $type, array('user' => $user_info));
  786. $userlist[] = $userdata["user"];
  787. }
  788. $userlist = array("users" => $userlist);
  789. } else
  790. die(api_error($a, $type, t("User not found.")));
  791. } else
  792. die(api_error($a, $type, t("User not found.")));
  793. return ($userlist);
  794. }
  795. api_register_func('api/users/search','api_users_search');
  796. /**
  797. *
  798. * http://