Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

2620 líneas
82KB

  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://developer.twitter.com/doc/get/statuses/home_timeline
  799. *
  800. * TODO: Optional parameters
  801. * TODO: Add reply info
  802. */
  803. function api_statuses_home_timeline(&$a, $type){
  804. if (api_user()===false) return false;
  805. unset($_REQUEST["user_id"]);
  806. unset($_GET["user_id"]);
  807. unset($_REQUEST["screen_name"]);
  808. unset($_GET["screen_name"]);
  809. $user_info = api_get_user($a);
  810. // get last newtork messages
  811. // params
  812. $count = (x($_REQUEST,'count')?$_REQUEST['count']:20);
  813. $page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
  814. if ($page<0) $page=0;
  815. $since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
  816. $max_id = (x($_REQUEST,'max_id')?$_REQUEST['max_id']:0);
  817. //$since_id = 0;//$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
  818. $exclude_replies = (x($_REQUEST,'exclude_replies')?1:0);
  819. $conversation_id = (x($_REQUEST,'conversation_id')?$_REQUEST['conversation_id']:0);
  820. $start = $page*$count;
  821. $sql_extra = '';
  822. if ($max_id > 0)
  823. $sql_extra .= ' AND `item`.`id` <= '.intval($max_id);
  824. if ($exclude_replies > 0)
  825. $sql_extra .= ' AND `item`.`parent` = `item`.`id`';
  826. if ($conversation_id > 0)
  827. $sql_extra .= ' AND `item`.`parent` = '.intval($conversation_id);
  828. $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
  829. `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
  830. `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
  831. `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
  832. FROM `item`, `contact`
  833. WHERE `item`.`uid` = %d AND `verb` = '%s'
  834. AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0
  835. AND `contact`.`id` = `item`.`contact-id`
  836. AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
  837. $sql_extra
  838. AND `item`.`id`>%d
  839. ORDER BY `item`.`id` DESC LIMIT %d ,%d ",
  840. intval(api_user()),
  841. dbesc(ACTIVITY_POST),
  842. intval($since_id),
  843. intval($start), intval($count)
  844. );
  845. $ret = api_format_items($r,$user_info);
  846. // We aren't going to try to figure out at the item, group, and page
  847. // level which items you've seen and which you haven't. If you're looking
  848. // at the network timeline just mark everything seen.
  849. $r = q("UPDATE `item` SET `unseen` = 0
  850. WHERE `unseen` = 1 AND `uid` = %d",
  851. //intval($user_info['uid'])
  852. intval(api_user())
  853. );
  854. $data = array('$statuses' => $ret);
  855. switch($type){
  856. case "atom":
  857. case "rss":
  858. $data = api_rss_extra($a, $data, $user_info);
  859. break;
  860. case "as":
  861. $as = api_format_as($a, $ret, $user_info);
  862. $as['title'] = $a->config['sitename']." Home Timeline";
  863. $as['link']['url'] = $a->get_baseurl()."/".$user_info["screen_name"]."/all";
  864. return($as);
  865. break;
  866. }
  867. return api_apply_template("timeline", $type, $data);
  868. }
  869. api_register_func('api/statuses/home_timeline','api_statuses_home_timeline', true);
  870. api_register_func('api/statuses/friends_timeline','api_statuses_home_timeline', true);
  871. function api_statuses_public_timeline(&$a, $type){
  872. if (api_user()===false) return false;
  873. $user_info = api_get_user($a);
  874. // get last newtork messages
  875. // params
  876. $count = (x($_REQUEST,'count')?$_REQUEST['count']:20);
  877. $page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
  878. if ($page<0) $page=0;
  879. $since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
  880. $max_id = (x($_REQUEST,'max_id')?$_REQUEST['max_id']:0);
  881. //$since_id = 0;//$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
  882. $exclude_replies = (x($_REQUEST,'exclude_replies')?1:0);
  883. $conversation_id = (x($_REQUEST,'conversation_id')?$_REQUEST['conversation_id']:0);
  884. $start = $page*$count;
  885. if ($max_id > 0)
  886. $sql_extra = 'AND `item`.`id` <= '.intval($max_id);
  887. if ($exclude_replies > 0)
  888. $sql_extra .= ' AND `item`.`parent` = `item`.`id`';
  889. if ($conversation_id > 0)
  890. $sql_extra .= ' AND `item`.`parent` = '.intval($conversation_id);
  891. $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
  892. `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
  893. `contact`.`network`, `contact`.`thumb`, `contact`.`self`, `contact`.`writable`,
  894. `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`,
  895. `user`.`nickname`, `user`.`hidewall`
  896. FROM `item` STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
  897. STRAIGHT_JOIN `user` ON `user`.`uid` = `item`.`uid`
  898. WHERE `verb` = '%s' AND `item`.`visible` = 1 AND `item`.`deleted` = 0 and `item`.`moderated` = 0
  899. AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = ''
  900. AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = ''
  901. AND `item`.`private` = 0 AND `item`.`wall` = 1 AND `user`.`hidewall` = 0
  902. AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
  903. $sql_extra
  904. AND `item`.`id`>%d
  905. ORDER BY `item`.`id` DESC LIMIT %d, %d ",
  906. dbesc(ACTIVITY_POST),
  907. intval($since_id),
  908. intval($start),
  909. intval($count));
  910. $ret = api_format_items($r,$user_info);
  911. $data = array('$statuses' => $ret);
  912. switch($type){
  913. case "atom":
  914. case "rss":
  915. $data = api_rss_extra($a, $data, $user_info);
  916. break;
  917. case "as":
  918. $as = api_format_as($a, $ret, $user_info);
  919. $as['title'] = $a->config['sitename']." Public Timeline";
  920. $as['link']['url'] = $a->get_baseurl()."/";
  921. return($as);
  922. break;
  923. }
  924. return api_apply_template("timeline", $type, $data);
  925. }
  926. api_register_func('api/statuses/public_timeline','api_statuses_public_timeline', true);
  927. /**
  928. *
  929. */
  930. function api_statuses_show(&$a, $type){
  931. if (api_user()===false) return false;
  932. $user_info = api_get_user($a);
  933. // params
  934. $id = intval($a->argv[3]);
  935. if ($id == 0)
  936. $id = intval($_REQUEST["id"]);
  937. // Hotot workaround
  938. if ($id == 0)
  939. $id = intval($a->argv[4]);
  940. logger('API: api_statuses_show: '.$id);
  941. $conversation = (x($_REQUEST,'conversation')?1:0);
  942. $sql_extra = '';
  943. if ($conversation)
  944. $sql_extra .= " AND `item`.`parent` = %d ORDER BY `received` ASC ";
  945. else
  946. $sql_extra .= " AND `item`.`id` = %d";
  947. $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
  948. `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
  949. `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
  950. `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
  951. FROM `item`, `contact`
  952. WHERE `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0
  953. AND `contact`.`id` = `item`.`contact-id` AND `item`.`uid` = %d AND `item`.`verb` = '%s'
  954. AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
  955. $sql_extra",
  956. intval(api_user()),
  957. dbesc(ACTIVITY_POST),
  958. intval($id)
  959. );
  960. if (!$r)
  961. die(api_error($a, $type, t("There is no status with this id.")));
  962. $ret = api_format_items($r,$user_info);
  963. if ($conversation) {
  964. $data = array('$statuses' => $ret);
  965. return api_apply_template("timeline", $type, $data);
  966. } else {
  967. $data = array('$status' => $ret[0]);
  968. /*switch($type){
  969. case "atom":
  970. case "rss":
  971. $data = api_rss_extra($a, $data, $user_info);
  972. }*/
  973. return api_apply_template("status", $type, $data);
  974. }
  975. }
  976. api_register_func('api/statuses/show','api_statuses_show', true);
  977. /**
  978. *
  979. */
  980. function api_conversation_show(&$a, $type){
  981. if (api_user()===false) return false;
  982. $user_info = api_get_user($a);
  983. // params
  984. $id = intval($a->argv[3]);
  985. $count = (x($_REQUEST,'count')?$_REQUEST['count']:20);
  986. $page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
  987. if ($page<0) $page=0;
  988. $since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
  989. $max_id = (x($_REQUEST,'max_id')?$_REQUEST['max_id']:0);
  990. $start = $page*$count;
  991. if ($id == 0)
  992. $id = intval($_REQUEST["id"]);
  993. // Hotot workaround
  994. if ($id == 0)
  995. $id = intval($a->argv[4]);
  996. logger('API: api_conversation_show: '.$id);
  997. $sql_extra = '';
  998. if ($max_id > 0)
  999. $sql_extra = ' AND `item`.`id` <= '.intval($max_id);
  1000. $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
  1001. `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
  1002. `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
  1003. `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
  1004. FROM `item` INNER JOIN (SELECT `uri`,`parent` FROM `item` WHERE `id` = %d) AS `temp1`
  1005. ON (`item`.`thr-parent` = `temp1`.`uri` AND `item`.`parent` = `temp1`.`parent`), `contact`
  1006. WHERE `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0
  1007. AND `item`.`uid` = %d AND `item`.`verb` = '%s' AND `contact`.`id` = `item`.`contact-id`
  1008. AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
  1009. AND `item`.`id`>%d $sql_extra
  1010. ORDER BY `item`.`id` DESC LIMIT %d ,%d",
  1011. intval($id), intval(api_user()),
  1012. dbesc(ACTIVITY_POST),
  1013. intval($since_id),
  1014. intval($start), intval($count)
  1015. );
  1016. if (!$r)
  1017. die(api_error($a, $type, t("There is no conversation with this id.")));
  1018. $ret = api_format_items($r,$user_info);
  1019. $data = array('$statuses' => $ret);
  1020. return api_apply_template("timeline", $type, $data);
  1021. }
  1022. api_register_func('api/conversation/show','api_conversation_show', true);
  1023. /**
  1024. *
  1025. */
  1026. function api_statuses_repeat(&$a, $type){
  1027. global $called_api;
  1028. if (api_user()===false) return false;
  1029. $user_info = api_get_user($a);
  1030. // params
  1031. $id = intval($a->argv[3]);
  1032. if ($id == 0)
  1033. $id = intval($_REQUEST["id"]);
  1034. // Hotot workaround
  1035. if ($id == 0)
  1036. $id = intval($a->argv[4]);
  1037. logger('API: api_statuses_repeat: '.$id);
  1038. $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, `contact`.`nick` as `reply_author`,
  1039. `contact`.`name`, `contact`.`photo` as `reply_photo`, `contact`.`url` as `reply_url`, `contact`.`rel`,
  1040. `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
  1041. `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
  1042. FROM `item`, `contact`
  1043. WHERE `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0
  1044. AND `contact`.`id` = `item`.`contact-id`
  1045. AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
  1046. $sql_extra
  1047. AND `item`.`id`=%d",
  1048. intval($id)
  1049. );
  1050. if ($r[0]['body'] != "") {
  1051. if (!intval(get_config('system','old_share'))) {
  1052. if (strpos($r[0]['body'], "[/share]") !== false) {
  1053. $pos = strpos($r[0]['body'], "[share");
  1054. $post = substr($r[0]['body'], $pos);
  1055. } else {
  1056. $post = "[share author='".str_replace("'", "&#039;", $r[0]['author-name']).
  1057. "' profile='".$r[0]['author-link'].
  1058. "' avatar='".$r[0]['author-avatar'].
  1059. "' link='".$r[0]['plink']."']";
  1060. $post .= $r[0]['body'];
  1061. $post .= "[/share]";
  1062. }
  1063. $_REQUEST['body'] = $post;
  1064. } else
  1065. $_REQUEST['body'] = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8')."[url=".$r[0]['reply_url']."]".$r[0]['reply_author']."[/url] \n".$r[0]['body'];
  1066. $_REQUEST['profile_uid'] = api_user();
  1067. $_REQUEST['type'] = 'wall';
  1068. $_REQUEST['api_source'] = true;
  1069. require_once('mod/item.php');
  1070. item_post($a);
  1071. }
  1072. // this should output the last post (the one we just posted).
  1073. $called_api = null;
  1074. return(api_status_show($a,$type));
  1075. }
  1076. api_register_func('api/statuses/retweet','api_statuses_repeat', true);
  1077. /**
  1078. *
  1079. */
  1080. function api_statuses_destroy(&$a, $type){
  1081. if (api_user()===false) return false;
  1082. $user_info = api_get_user($a);
  1083. // params
  1084. $id = intval($a->argv[3]);
  1085. if ($id == 0)
  1086. $id = intval($_REQUEST["id"]);
  1087. // Hotot workaround
  1088. if ($id == 0)
  1089. $id = intval($a->argv[4]);
  1090. logger('API: api_statuses_destroy: '.$id);
  1091. $ret = api_statuses_show($a, $type);
  1092. require_once('include/items.php');
  1093. drop_item($id, false);
  1094. return($ret);
  1095. }
  1096. api_register_func('api/statuses/destroy','api_statuses_destroy', true);
  1097. /**
  1098. *
  1099. * http://developer.twitter.com/doc/get/statuses/mentions
  1100. *
  1101. */
  1102. function api_statuses_mentions(&$a, $type){
  1103. if (api_user()===false) return false;
  1104. unset($_REQUEST["user_id"]);
  1105. unset($_GET["user_id"]);
  1106. unset($_REQUEST["screen_name"]);
  1107. unset($_GET["screen_name"]);
  1108. $user_info = api_get_user($a);
  1109. // get last newtork messages
  1110. // params
  1111. $count = (x($_REQUEST,'count')?$_REQUEST['count']:20);
  1112. $page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
  1113. if ($page<0) $page=0;
  1114. $since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
  1115. $max_id = (x($_REQUEST,'max_id')?$_REQUEST['max_id']:0);
  1116. //$since_id = 0;//$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
  1117. $start = $page*$count;
  1118. // Ugly code - should be changed
  1119. $myurl = $a->get_baseurl() . '/profile/'. $a->user['nickname'];
  1120. $myurl = substr($myurl,strpos($myurl,'://')+3);
  1121. //$myurl = str_replace(array('www.','.'),array('','\\.'),$myurl);
  1122. $myurl = str_replace('www.','',$myurl);
  1123. $diasp_url = str_replace('/profile/','/u/',$myurl);
  1124. if ($max_id > 0)
  1125. $sql_extra = ' AND `item`.`id` <= '.intval($max_id);
  1126. $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
  1127. `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
  1128. `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
  1129. `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
  1130. FROM `item`, `contact`
  1131. WHERE `item`.`uid` = %d AND `verb` = '%s'
  1132. AND NOT (`item`.`author-link` IN ('https://%s', 'http://%s'))
  1133. AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0
  1134. AND `contact`.`id` = `item`.`contact-id`
  1135. AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
  1136. AND `item`.`parent` IN (SELECT `iid` from thread where uid = %d AND `mention`)
  1137. $sql_extra
  1138. AND `item`.`id`>%d
  1139. ORDER BY `item`.`id` DESC LIMIT %d ,%d ",
  1140. intval(api_user()),
  1141. dbesc(ACTIVITY_POST),
  1142. dbesc(protect_sprintf($myurl)),
  1143. dbesc(protect_sprintf($myurl)),
  1144. intval(api_user()),
  1145. intval($since_id),
  1146. intval($start), intval($count)
  1147. );
  1148. $ret = api_format_items($r,$user_info);
  1149. $data = array('$statuses' => $ret);
  1150. switch($type){
  1151. case "atom":
  1152. case "rss":
  1153. $data = api_rss_extra($a, $data, $user_info);
  1154. break;
  1155. case "as":
  1156. $as = api_format_as($a, $ret, $user_info);
  1157. $as["title"] = $a->config['sitename']." Mentions";
  1158. $as['link']['url'] = $a->get_baseurl()."/";
  1159. return($as);
  1160. break;
  1161. }
  1162. return api_apply_template("timeline", $type, $data);
  1163. }
  1164. api_register_func('api/statuses/mentions','api_statuses_mentions', true);
  1165. api_register_func('api/statuses/replies','api_statuses_mentions', true);
  1166. function api_statuses_user_timeline(&$a, $type){
  1167. if (api_user()===false) return false;
  1168. $user_info = api_get_user($a);
  1169. // get last network messages
  1170. logger("api_statuses_user_timeline: api_user: ". api_user() .
  1171. "\nuser_info: ".print_r($user_info, true) .
  1172. "\n_REQUEST: ".print_r($_REQUEST, true),
  1173. LOGGER_DEBUG);
  1174. // params
  1175. $count = (x($_REQUEST,'count')?$_REQUEST['count']:20);
  1176. $page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
  1177. if ($page<0) $page=0;
  1178. $since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
  1179. //$since_id = 0;//$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
  1180. $exclude_replies = (x($_REQUEST,'exclude_replies')?1:0);
  1181. $conversation_id = (x($_REQUEST,'conversation_id')?$_REQUEST['conversation_id']:0);
  1182. $start = $page*$count;
  1183. $sql_extra = '';
  1184. if ($user_info['self']==1)
  1185. $sql_extra .= " AND `item`.`wall` = 1 ";
  1186. if ($exclude_replies > 0)
  1187. $sql_extra .= ' AND `item`.`parent` = `item`.`id`';
  1188. if ($conversation_id > 0)
  1189. $sql_extra .= ' AND `item`.`parent` = '.intval($conversation_id);
  1190. $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
  1191. `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
  1192. `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
  1193. `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
  1194. FROM `item`, `contact`
  1195. WHERE `item`.`uid` = %d AND `verb` = '%s'
  1196. AND `item`.`contact-id` = %d
  1197. AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0
  1198. AND `contact`.`id` = `item`.`contact-id`
  1199. AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
  1200. $sql_extra
  1201. AND `item`.`id`>%d
  1202. ORDER BY `item`.`id` DESC LIMIT %d ,%d ",
  1203. intval(api_user()),
  1204. dbesc(ACTIVITY_POST),
  1205. intval($user_info['cid']),
  1206. intval($since_id),
  1207. intval($start), intval($count)
  1208. );
  1209. $ret = api_format_items($r,$user_info, true);
  1210. $data = array('$statuses' => $ret);
  1211. switch($type){
  1212. case "atom":
  1213. case "rss":
  1214. $data = api_rss_extra($a, $data, $user_info);
  1215. }
  1216. return api_apply_template("timeline", $type, $data);
  1217. }
  1218. api_register_func('api/statuses/user_timeline','api_statuses_user_timeline', true);
  1219. function api_favorites(&$a, $type){
  1220. global $called_api;
  1221. if (api_user()===false) return false;
  1222. $called_api= array();
  1223. $user_info = api_get_user($a);
  1224. // in friendica starred item are private
  1225. // return favorites only for self
  1226. logger('api_favorites: self:' . $user_info['self']);
  1227. if ($user_info['self']==0) {
  1228. $ret = array();
  1229. } else {
  1230. $sql_extra = "";
  1231. // params
  1232. $since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
  1233. $max_id = (x($_REQUEST,'max_id')?$_REQUEST['max_id']:0);
  1234. $count = (x($_GET,'count')?$_GET['count']:20);
  1235. $page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
  1236. if ($page<0) $page=0;
  1237. $start = $page*$count;
  1238. if ($max_id > 0)
  1239. $sql_extra .= ' AND `item`.`id` <= '.intval($max_id);
  1240. $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
  1241. `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
  1242. `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
  1243. `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
  1244. FROM `item`, `contact`
  1245. WHERE `item`.`uid` = %d AND `verb` = '%s'
  1246. AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0
  1247. AND `item`.`starred` = 1
  1248. AND `contact`.`id` = `item`.`contact-id`
  1249. AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
  1250. $sql_extra
  1251. AND `item`.`id`>%d
  1252. ORDER BY `item`.`id` DESC LIMIT %d ,%d ",
  1253. intval(api_user()),
  1254. dbesc(ACTIVITY_POST),
  1255. intval($since_id),
  1256. intval($start), intval($count)
  1257. );
  1258. $ret = api_format_items($r,$user_info);
  1259. }
  1260. $data = array('$statuses' => $ret);
  1261. switch($type){
  1262. case "atom":
  1263. case "rss":
  1264. $data = api_rss_extra($a, $data, $user_info);
  1265. }
  1266. return api_apply_template("timeline", $type, $data);
  1267. }
  1268. api_register_func('api/favorites','api_favorites', true);
  1269. function api_format_as($a, $ret, $user_info) {
  1270. $as = array();
  1271. $as['title'] = $a->config['sitename']." Public Timeline";
  1272. $items = array();
  1273. foreach ($ret as $item) {
  1274. $singleitem["actor"]["displayName"] = $item["user"]["name"];
  1275. $singleitem["actor"]["id"] = $item["user"]["contact_url"];
  1276. $avatar[0]["url"] = $item["user"]["profile_image_url"];
  1277. $avatar[0]["rel"] = "avatar";
  1278. $avatar[0]["type"] = "";
  1279. $avatar[0]["width"] = 96;
  1280. $avatar[0]["height"] = 96;
  1281. $avatar[1]["url"] = $item["user"]["profile_image_url"];
  1282. $avatar[1]["rel"] = "avatar";
  1283. $avatar[1]["type"] = "";
  1284. $avatar[1]["width"] = 48;
  1285. $avatar[1]["height"] = 48;
  1286. $avatar[2]["url"] = $item["user"]["profile_image_url"];
  1287. $avatar[2]["rel"] = "avatar";
  1288. $avatar[2]["type"] = "";
  1289. $avatar[2]["width"] = 24;
  1290. $avatar[2]["height"] = 24;
  1291. $singleitem["actor"]["avatarLinks"] = $avatar;
  1292. $singleitem["actor"]["image"]["url"] = $item["user"]["profile_image_url"];
  1293. $singleitem["actor"]["image"]["rel"] = "avatar";
  1294. $singleitem["actor"]["image"]["type"] = "";
  1295. $singleitem["actor"]["image"]["width"] = 96;
  1296. $singleitem["actor"]["image"]["height"] = 96;
  1297. $singleitem["actor"]["type"] = "person";
  1298. $singleitem["actor"]["url"] = $item["person"]["contact_url"];
  1299. $singleitem["actor"]["statusnet:profile_info"]["local_id"] = $item["user"]["id"];
  1300. $singleitem["actor"]["statusnet:profile_info"]["following"] = $item["user"]["following"] ? "true" : "false";
  1301. $singleitem["actor"]["statusnet:profile_info"]["blocking"] = "false";
  1302. $singleitem["actor"]["contact"]["preferredUsername"] = $item["user"]["screen_name"];
  1303. $singleitem["actor"]["contact"]["displayName"] = $item["user"]["name"];
  1304. $singleitem["actor"]["contact"]["addresses"] = "";
  1305. $singleitem["body"] = $item["text"];
  1306. $singleitem["object"]["displayName"] = $item["text"];
  1307. $singleitem["object"]["id"] = $item["url"];
  1308. $singleitem["object"]["type"] = "note";
  1309. $singleitem["object"]["url"] = $item["url"];
  1310. //$singleitem["context"] =;
  1311. $singleitem["postedTime"] = date("c", strtotime($item["published"]));
  1312. $singleitem["provider"]["objectType"] = "service";
  1313. $singleitem["provider"]["displayName"] = "Test";
  1314. $singleitem["provider"]["url"] = "http://test.tld";
  1315. $singleitem["title"] = $item["text"];
  1316. $singleitem["verb"] = "post";
  1317. $singleitem["statusnet:notice_info"]["local_id"] = $item["id"];
  1318. $singleitem["statusnet:notice_info"]["source"] = $item["source"];
  1319. $singleitem["statusnet:notice_info"]["favorite"] = "false";
  1320. $singleitem["statusnet:notice_info"]["repeated"] = "false";
  1321. //$singleitem["original"] = $item;
  1322. $items[] = $singleitem;
  1323. }
  1324. $as['items'] = $items;
  1325. $as['link']['url'] = $a->get_baseurl()."/".$user_info["screen_name"]."/all";
  1326. $as['link']['rel'] = "alternate";
  1327. $as['link']['type'] = "text/html";
  1328. return($as);
  1329. }
  1330. function api_format_messages($item, $recipient, $sender) {
  1331. // standard meta information
  1332. $ret=Array(
  1333. 'id' => $item['id'],
  1334. 'sender_id' => $sender['id'] ,
  1335. 'text' => "",
  1336. 'recipient_id' => $recipient['id'],
  1337. 'created_at' => api_date($item['created']),
  1338. 'sender_screen_name' => $sender['screen_name'],
  1339. 'recipient_screen_name' => $recipient['screen_name'],
  1340. 'sender' => $sender,
  1341. 'recipient' => $recipient,
  1342. );
  1343. // "uid" and "self" are only needed for some internal stuff, so remove it from here
  1344. unset($ret["sender"]["uid"]);
  1345. unset($ret["sender"]["self"]);
  1346. unset($ret["recipient"]["uid"]);
  1347. unset($ret["recipient"]["self"]);
  1348. //don't send title to regular StatusNET requests to avoid confusing these apps
  1349. if (x($_GET, 'getText')) {
  1350. $ret['title'] = $item['title'] ;
  1351. if ($_GET["getText"] == "html") {
  1352. $ret['text'] = bbcode($item['body'], false, false);
  1353. }
  1354. elseif ($_GET["getText"] == "plain") {
  1355. //$ret['text'] = html2plain(bbcode($item['body'], false, false, true), 0);
  1356. $ret['text'] = trim(html2plain(bbcode(api_clean_plain_items($item['body']), false, false, 2, true), 0));
  1357. }
  1358. }
  1359. else {
  1360. $ret['text'] = $item['title']."\n".html2plain(bbcode(api_clean_plain_items($item['body']), false, false, 2, true), 0);
  1361. }
  1362. if (isset($_GET["getUserObjects"]) && $_GET["getUserObjects"] == "false") {
  1363. unset($ret['sender']);
  1364. unset($ret['recipient']);
  1365. }
  1366. return $ret;
  1367. }
  1368. function api_get_entitities(&$text, $bbcode) {
  1369. /*
  1370. To-Do:
  1371. * Links at the first character of the post
  1372. */
  1373. $a = get_app();
  1374. $include_entities = strtolower(x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:"false");
  1375. if ($include_entities != "true") {
  1376. require_once("mod/proxy.php");
  1377. preg_match_all("/\[img](.*?)\[\/img\]/ism", $bbcode, $images);
  1378. foreach ($images[1] AS $image) {
  1379. $replace = proxy_url($image);
  1380. $text = str_replace($image, $replace, $text);
  1381. }
  1382. return array();
  1383. }
  1384. $bbcode = bb_CleanPictureLinks($bbcode);
  1385. // Change pure links in text to bbcode uris
  1386. $bbcode = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2]$2[/url]', $bbcode);
  1387. $entities = array();
  1388. $entities["hashtags"] = array();
  1389. $entities["symbols"] = array();
  1390. $entities["urls"] = array();
  1391. $entities["user_mentions"] = array();
  1392. $URLSearchString = "^\[\]";
  1393. $bbcode = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",'#$2',$bbcode);
  1394. $bbcode = preg_replace("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism",'[url=$1]$2[/url]',$bbcode);
  1395. //$bbcode = preg_replace("/\[url\](.*?)\[\/url\]/ism",'[url=$1]$1[/url]',$bbcode);
  1396. $bbcode = preg_replace("/\[video\](.*?)\[\/video\]/ism",'[url=$1]$1[/url]',$bbcode);
  1397. $bbcode = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism",
  1398. '[url=https://www.youtube.com/watch?v=$1]https://www.youtube.com/watch?v=$1[/url]', $bbcode);
  1399. $bbcode = preg_replace("/\[youtube\](.*?)\[\/youtube\]/ism",'[url=$1]$1[/url]',$bbcode);
  1400. $bbcode = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism",
  1401. '[url=https://vimeo.com/$1]https://vimeo.com/$1[/url]', $bbcode);
  1402. $bbcode = preg_replace("/\[vimeo\](.*?)\[\/vimeo\]/ism",'[url=$1]$1[/url]',$bbcode);
  1403. $bbcode = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $bbcode);
  1404. //preg_match_all("/\[url\]([$URLSearchString]*)\[\/url\]/ism", $bbcode, $urls1);
  1405. preg_match_all("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $bbcode, $urls);
  1406. $ordered_urls = array();
  1407. foreach ($urls[1] AS $id=>$url) {
  1408. //$start = strpos($text, $url, $offset);
  1409. $start = iconv_strpos($text, $url, 0, "UTF-8");
  1410. if (!($start === false))
  1411. $ordered_urls[$start] = array("url" => $url, "title" => $urls[2][$id]);
  1412. }
  1413. ksort($ordered_urls);
  1414. $offset = 0;
  1415. //foreach ($urls[1] AS $id=>$url) {
  1416. foreach ($ordered_urls AS $url) {
  1417. if ((substr($url["title"], 0, 7) != "http://") AND (substr($url["title"], 0, 8) != "https://") AND
  1418. !strpos($url["title"], "http://") AND !strpos($url["title"], "https://"))
  1419. $display_url = $url["title"];
  1420. else {
  1421. $display_url = str_replace(array("http://www.", "https://www."), array("", ""), $url["url"]);
  1422. $display_url = str_replace(array("http://", "https://"), array("", ""), $display_url);
  1423. if (strlen($display_url) > 26)
  1424. $display_url = substr($display_url, 0, 25)."…";
  1425. }
  1426. //$start = strpos($text, $url, $offset);
  1427. $start = iconv_strpos($text, $url["url"], $offset, "UTF-8");
  1428. if (!($start === false)) {
  1429. $entities["urls"][] = array("url" => $url["url"],
  1430. "expanded_url" => $url["url"],
  1431. "display_url" => $display_url,
  1432. "indices" => array($start, $start+strlen($url["url"])));
  1433. $offset = $start + 1;
  1434. }
  1435. }
  1436. preg_match_all("/\[img](.*?)\[\/img\]/ism", $bbcode, $images);
  1437. $ordered_images = array();
  1438. foreach ($images[1] AS $image) {
  1439. //$start = strpos($text, $url, $offset);
  1440. $start = iconv_strpos($text, $image, 0, "UTF-8");
  1441. if (!($start === false))
  1442. $ordered_images[$start] = $image;
  1443. }
  1444. //$entities["media"] = array();
  1445. $offset = 0;
  1446. foreach ($ordered_images AS $url) {
  1447. $display_url = str_replace(array("http://www.", "https://www."), array("", ""), $url);
  1448. $display_url = str_replace(array("http://", "https://"), array("", ""), $display_url);
  1449. if (strlen($display_url) > 26)
  1450. $display_url = substr($display_url, 0, 25)."…";
  1451. $start = iconv_strpos($text, $url, $offset, "UTF-8");
  1452. if (!($start === false)) {
  1453. require_once("include/Photo.php");
  1454. $image = get_photo_info($url);
  1455. if ($image) {
  1456. // If image cache is activated, then use the following sizes:
  1457. // thumb (150), small (340), medium (600) and large (1024)
  1458. if (!get_config("system", "proxy_disabled")) {
  1459. require_once("mod/proxy.php");
  1460. $media_url = proxy_url($url);
  1461. $sizes = array();
  1462. $scale = scale_image($image[0], $image[1], 150);
  1463. $sizes["thumb"] = array("w" => $scale["width"], "h" => $scale["height"], "resize" => "fit");
  1464. if (($image[0] > 150) OR ($image[1] > 150)) {
  1465. $scale = scale_image($image[0], $image[1], 340);
  1466. $sizes["small"] = array("w" => $scale["width"], "h" => $scale["height"], "resize" => "fit");
  1467. }
  1468. $scale = scale_image($image[0], $image[1], 600);
  1469. $sizes["medium"] = array("w" => $scale["width"], "h" => $scale["height"], "resize" => "fit");
  1470. if (($image[0] > 600) OR ($image[1] > 600)) {
  1471. $scale = scale_image($image[0], $image[1], 1024);
  1472. $sizes["large"] = array("w" => $scale["width"], "h" => $scale["height"], "resize" => "fit");
  1473. }
  1474. } else {
  1475. $media_url = $url;
  1476. $sizes["medium"] = array("w" => $image[0], "h" => $image[1], "resize" => "fit");
  1477. }
  1478. $entities["media"][] = array(
  1479. "id" => $start+1,
  1480. "id_str" => (string)$start+1,
  1481. "indices" => array($start, $start+strlen($url)),
  1482. "media_url" => normalise_link($media_url),
  1483. "media_url_https" => $media_url,
  1484. "url" => $url,
  1485. "display_url" => $display_url,
  1486. "expanded_url" => $url,
  1487. "type" => "photo",
  1488. "sizes" => $sizes);
  1489. }
  1490. $offset = $start + 1;
  1491. }
  1492. }
  1493. return($entities);
  1494. }
  1495. function api_format_items($r,$user_info, $filter_user = false) {
  1496. $a = get_app();
  1497. $ret = Array();
  1498. foreach($r as $item) {
  1499. api_share_as_retweet($a, api_user(), $item);
  1500. localize_item($item);
  1501. $status_user = api_item_get_user($a,$item);
  1502. // Look if the posts are matching if they should be filtered by user id
  1503. if ($filter_user AND ($status_user["id"] != $user_info["id"]))
  1504. continue;
  1505. if ($item['thr-parent'] != $item['uri']) {
  1506. $r = q("SELECT id FROM item WHERE uid=%d AND uri='%s' LIMIT 1",
  1507. intval(api_user()),
  1508. dbesc($item['thr-parent']));
  1509. if ($r)
  1510. $in_reply_to_status_id = intval($r[0]['id']);
  1511. else
  1512. $in_reply_to_status_id = intval($item['parent']);
  1513. $in_reply_to_status_id_str = (string) intval($item['parent']);
  1514. $in_reply_to_screen_name = NULL;
  1515. $in_reply_to_user_id = NULL;
  1516. $in_reply_to_user_id_str = NULL;
  1517. $r = q("SELECT `author-link` FROM item WHERE uid=%d AND id=%d LIMIT 1",
  1518. intval(api_user()),
  1519. intval($in_reply_to_status_id));
  1520. if ($r) {
  1521. $r = q("SELECT * FROM unique_contacts WHERE `url` = '%s'", dbesc(normalise_link($r[0]['author-link'])));
  1522. if ($r) {
  1523. if ($r[0]['nick'] == "")
  1524. $r[0]['nick'] = api_get_nick($r[0]["url"]);
  1525. $in_reply_to_screen_name = (($r[0]['nick']) ? $r[0]['nick'] : $r[0]['name']);
  1526. $in_reply_to_user_id = intval($r[0]['id']);
  1527. $in_reply_to_user_id_str = (string) intval($r[0]['id']);
  1528. }
  1529. }
  1530. } else {
  1531. $in_reply_to_screen_name = NULL;
  1532. $in_reply_to_user_id = NULL;
  1533. $in_reply_to_status_id = NULL;
  1534. $in_reply_to_user_id_str = NULL;
  1535. $in_reply_to_status_id_str = NULL;
  1536. }
  1537. // Workaround for ostatus messages where the title is identically to the body
  1538. //$statusbody = trim(html2plain(bbcode(api_clean_plain_items($item['body']), false, false, 5, true), 0));
  1539. $html = bbcode(api_clean_plain_items($item['body']), false, false, 2, true);
  1540. $statusbody = trim(html2plain($html, 0));
  1541. $statustitle = trim($item['title']);
  1542. if (($statustitle != '') and (strpos($statusbody, $statustitle) !== false))
  1543. $statustext = trim($statusbody);
  1544. else
  1545. $statustext = trim($statustitle."\n\n".$statusbody);
  1546. if (($item["network"] == NETWORK_FEED) and (strlen($statustext)> 1000))
  1547. $statustext = substr($statustext, 0, 1000)."... \n".$item["plink"];
  1548. $status = array(
  1549. 'text' => $statustext,
  1550. 'truncated' => False,
  1551. 'created_at'=> api_date($item['created']),
  1552. 'in_reply_to_status_id' => $in_reply_to_status_id,
  1553. 'in_reply_to_status_id_str' => $in_reply_to_status_id_str,
  1554. 'source' => (($item['app']) ? $item['app'] : 'web'),
  1555. 'id' => intval($item['id']),
  1556. 'id_str' => (string) intval($item['id']),
  1557. 'in_reply_to_user_id' => $in_reply_to_user_id,
  1558. 'in_reply_to_user_id_str' => $in_reply_to_user_id_str,
  1559. 'in_reply_to_screen_name' => $in_reply_to_screen_name,
  1560. 'geo' => NULL,
  1561. 'favorited' => $item['starred'] ? true : false,
  1562. //'attachments' => array(),
  1563. 'user' => $status_user ,
  1564. //'entities' => NULL,
  1565. 'statusnet_html' => trim(bbcode($item['body'], false, false)),
  1566. 'statusnet_conversation_id' => $item['parent'],
  1567. );
  1568. if ($item['title'] != "")
  1569. $status['statusnet_html'] = "<h4>".bbcode($item['title'])."</h4>\n".$status['statusnet_html'];
  1570. $entities = api_get_entitities($status['text'], $item['body']);
  1571. if (count($entities) > 0)
  1572. $status['entities'] = $entities;
  1573. if (($item['item_network'] != "") AND ($status["source"] == 'web'))
  1574. $status["source"] = network_to_name($item['item_network']);
  1575. else if (($item['item_network'] != "") AND (network_to_name($item['item_network']) != $status["source"]))
  1576. $status["source"] = trim($status["source"].' ('.network_to_name($item['item_network']).')');
  1577. // Retweets are only valid for top postings
  1578. // It doesn't work reliable with the link if its a feed
  1579. $IsRetweet = ($item['owner-link'] != $item['author-link']);
  1580. if ($IsRetweet)
  1581. $IsRetweet = (($item['owner-name'] != $item['author-name']) OR ($item['owner-avatar'] != $item['author-avatar']));
  1582. if ($IsRetweet AND ($item["id"] == $item["parent"])) {
  1583. $retweeted_status = $status;
  1584. $retweeted_status["user"] = api_get_user($a,$item["author-link"]);
  1585. $status["retweeted_status"] = $retweeted_status;
  1586. }
  1587. // "uid" and "self" are only needed for some internal stuff, so remove it from here
  1588. unset($status["user"]["uid"]);
  1589. unset($status["user"]["self"]);
  1590. // 'geo' => array('type' => 'Point',
  1591. // 'coordinates' => array((float) $notice->lat,
  1592. // (float) $notice->lon));
  1593. $ret[] = $status;
  1594. };
  1595. return $ret;
  1596. }
  1597. function api_account_rate_limit_status(&$a,$type) {
  1598. $hash = array(
  1599. 'reset_time_in_seconds' => strtotime('now + 1 hour'),
  1600. 'remaining_hits' => (string) 150,
  1601. 'hourly_limit' => (string) 150,
  1602. 'reset_time' => api_date(datetime_convert('UTC','UTC','now + 1 hour',ATOM_TIME)),
  1603. );
  1604. if ($type == "xml")
  1605. $hash['resettime_in_seconds'] = $hash['reset_time_in_seconds'];
  1606. return api_apply_template('ratelimit', $type, array('$hash' => $hash));
  1607. }
  1608. api_register_func('api/account/rate_limit_status','api_account_rate_limit_status',true);
  1609. function api_help_test(&$a,$type) {
  1610. if ($type == 'xml')
  1611. $ok = "true";
  1612. else
  1613. $ok = "ok";
  1614. return api_apply_template('test', $type, array("$ok" => $ok));
  1615. }
  1616. api_register_func('api/help/test','api_help_test',false);
  1617. function api_lists(&$a,$type) {
  1618. $ret = array();
  1619. return array($ret);
  1620. }
  1621. api_register_func('api/lists','api_lists',true);
  1622. function api_lists_list(&$a,$type) {
  1623. $ret = array();
  1624. return array($ret);
  1625. }
  1626. api_register_func('api/lists/list','api_lists_list',true);
  1627. /**
  1628. * https://dev.twitter.com/docs/api/1/get/statuses/friends
  1629. * This function is deprecated by Twitter
  1630. * returns: json, xml
  1631. **/
  1632. function api_statuses_f(&$a, $type, $qtype) {
  1633. if (api_user()===false) return false;
  1634. $user_info = api_get_user($a);
  1635. if (x($_GET,'cursor') && $_GET['cursor']=='undefined'){
  1636. /* this is to stop Hotot to load friends multiple times
  1637. * I'm not sure if I'm missing return something or
  1638. * is a bug in hotot. Workaround, meantime
  1639. */
  1640. /*$ret=Array();
  1641. return array('$users' => $ret);*/
  1642. return false;
  1643. }
  1644. if($qtype == 'friends')
  1645. $sql_extra = sprintf(" AND ( `rel` = %d OR `rel` = %d ) ", intval(CONTACT_IS_SHARING), intval(CONTACT_IS_FRIEND));
  1646. if($qtype == 'followers')
  1647. $sql_extra = sprintf(" AND ( `rel` = %d OR `rel` = %d ) ", intval(CONTACT_IS_FOLLOWER), intval(CONTACT_IS_FRIEND));
  1648. // friends and followers only for self
  1649. if ($user_info['self'] == 0)
  1650. $sql_extra = " AND false ";
  1651. $r = q("SELECT `nurl` FROM `contact` WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 $sql_extra",
  1652. intval(api_user())
  1653. );
  1654. $ret = array();
  1655. foreach($r as $cid){
  1656. $user = api_get_user($a, $cid['nurl']);
  1657. // "uid" and "self" are only needed for some internal stuff, so remove it from here
  1658. unset($user["uid"]);
  1659. unset($user["self"]);
  1660. if ($user)
  1661. $ret[] = $user;
  1662. }
  1663. return array('$users' => $ret);
  1664. }
  1665. function api_statuses_friends(&$a, $type){
  1666. $data = api_statuses_f($a,$type,"friends");
  1667. if ($data===false) return false;
  1668. return api_apply_template("friends", $type, $data);
  1669. }
  1670. function api_statuses_followers(&$a, $type){
  1671. $data = api_statuses_f($a,$type,"followers");
  1672. if ($data===false) return false;
  1673. return api_apply_template("friends", $type, $data);
  1674. }
  1675. api_register_func('api/statuses/friends','api_statuses_friends',true);
  1676. api_register_func('api/statuses/followers','api_statuses_followers',true);
  1677. function api_statusnet_config(&$a,$type) {
  1678. $name = $a->config['sitename'];
  1679. $server = $a->get_hostname();
  1680. $logo = $a->get_baseurl() . '/images/friendica-64.png';
  1681. $email = $a->config['admin_email'];
  1682. $closed = (($a->config['register_policy'] == REGISTER_CLOSED) ? 'true' : 'false');
  1683. $private = (($a->config['system']['block_public']) ? 'true' : 'false');
  1684. $textlimit = (string) (($a->config['max_import_size']) ? $a->config['max_import_size'] : 200000);
  1685. if($a->config['api_import_size'])
  1686. $texlimit = string($a->config['api_import_size']);
  1687. $ssl = (($a->config['system']['have_ssl']) ? 'true' : 'false');
  1688. $sslserver = (($ssl === 'true') ? str_replace('http:','https:',$a->get_baseurl()) : '');
  1689. $config = array(
  1690. 'site' => array('name' => $name,'server' => $server, 'theme' => 'default', 'path' => '',
  1691. 'logo' => $logo, 'fancy' => true, 'language' => 'en', 'email' => $email, 'broughtby' => '',
  1692. 'broughtbyurl' => '', 'timezone' => 'UTC', 'closed' => $closed, 'inviteonly' => false,
  1693. 'private' => $private, 'textlimit' => $textlimit, 'sslserver' => $sslserver, 'ssl' => $ssl,
  1694. 'shorturllength' => '30',
  1695. 'friendica' => array(
  1696. 'FRIENDICA_PLATFORM' => FRIENDICA_PLATFORM,
  1697. 'FRIENDICA_VERSION' => FRIENDICA_VERSION,
  1698. 'DFRN_PROTOCOL_VERSION' => DFRN_PROTOCOL_VERSION,
  1699. 'DB_UPDATE_VERSION' => DB_UPDATE_VERSION
  1700. )
  1701. ),
  1702. );
  1703. return api_apply_template('config', $type, array('$config' => $config));
  1704. }
  1705. api_register_func('api/statusnet/config','api_statusnet_config',false);
  1706. function api_statusnet_version(&$a,$type) {
  1707. // liar
  1708. if($type === 'xml') {
  1709. header("Content-type: application/xml");
  1710. echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n" . '<version>0.9.7</version>' . "\r\n";
  1711. killme();
  1712. }
  1713. elseif($type === 'json') {
  1714. header("Content-type: application/json");
  1715. echo '"0.9.7"';
  1716. killme();
  1717. }
  1718. }
  1719. api_register_func('api/statusnet/version','api_statusnet_version',false);
  1720. function api_ff_ids(&$a,$type,$qtype) {
  1721. if(! api_user())
  1722. return false;
  1723. $user_info = api_get_user($a);
  1724. if($qtype == 'friends')
  1725. $sql_extra = sprintf(" AND ( `rel` = %d OR `rel` = %d ) ", intval(CONTACT_IS_SHARING), intval(CONTACT_IS_FRIEND));
  1726. if($qtype == 'followers')
  1727. $sql_extra = sprintf(" AND ( `rel` = %d OR `rel` = %d ) ", intval(CONTACT_IS_FOLLOWER), intval(CONTACT_IS_FRIEND));
  1728. if (!$user_info["self"])
  1729. $sql_extra = " AND false ";
  1730. $stringify_ids = (x($_REQUEST,'stringify_ids')?$_REQUEST['stringify_ids']:false);
  1731. $r = q("SELECT unique_contacts.id FROM contact, unique_contacts WHERE contact.nurl = unique_contacts.url AND `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 $sql_extra",
  1732. intval(api_user())
  1733. );
  1734. if(is_array($r)) {
  1735. if($type === 'xml') {
  1736. header("Content-type: application/xml");
  1737. echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n" . '<ids>' . "\r\n";
  1738. foreach($r as $rr)
  1739. echo '<id>' . $rr['id'] . '</id>' . "\r\n";
  1740. echo '</ids>' . "\r\n";
  1741. killme();
  1742. }
  1743. elseif($type === 'json') {
  1744. $ret = array();
  1745. header("Content-type: application/json");
  1746. foreach($r as $rr)
  1747. if ($stringify_ids)
  1748. $ret[] = $rr['id'];
  1749. else
  1750. $ret[] = intval($rr['id']);
  1751. echo json_encode($ret);
  1752. killme();
  1753. }
  1754. }
  1755. }
  1756. function api_friends_ids(&$a,$type) {
  1757. api_ff_ids($a,$type,'friends');
  1758. }
  1759. function api_followers_ids(&$a,$type) {
  1760. api_ff_ids($a,$type,'followers');
  1761. }
  1762. api_register_func('api/friends/ids','api_friends_ids',true);
  1763. api_register_func('api/followers/ids','api_followers_ids',true);
  1764. function api_direct_messages_new(&$a, $type) {
  1765. if (api_user()===false) return false;
  1766. if (!x($_POST, "text") OR (!x($_POST,"screen_name") AND !x($_POST,"user_id"))) return;
  1767. $sender = api_get_user($a);
  1768. require_once("include/message.php");
  1769. if ($_POST['screen_name']) {
  1770. $r = q("SELECT `id`, `nurl`, `network` FROM `contact` WHERE `uid`=%d AND `nick`='%s'",
  1771. intval(api_user()),
  1772. dbesc($_POST['screen_name']));
  1773. // Selecting the id by priority, friendica first
  1774. api_best_nickname($r);
  1775. $recipient = api_get_user($a, $r[0]['nurl']);
  1776. } else
  1777. $recipient = api_get_user($a, $_POST['user_id']);
  1778. $replyto = '';
  1779. $sub = '';
  1780. if (x($_REQUEST,'replyto')) {
  1781. $r = q('SELECT `parent-uri`, `title` FROM `mail` WHERE `uid`=%d AND `id`=%d',
  1782. intval(api_user()),
  1783. intval($_REQUEST['replyto']));
  1784. $replyto = $r[0]['parent-uri'];
  1785. $sub = $r[0]['title'];
  1786. }
  1787. else {
  1788. if (x($_REQUEST,'title')) {
  1789. $sub = $_REQUEST['title'];
  1790. }
  1791. else {
  1792. $sub = ((strlen($_POST['text'])>10)?substr($_POST['text'],0,10)."...":$_POST['text']);
  1793. }
  1794. }
  1795. $id = send_message($recipient['cid'], $_POST['text'], $sub, $replyto);
  1796. if ($id>-1) {
  1797. $r = q("SELECT * FROM `mail` WHERE id=%d", intval($id));
  1798. $ret = api_format_messages($r[0], $recipient, $sender);
  1799. } else {
  1800. $ret = array("error"=>$id);
  1801. }
  1802. $data = Array('$messages'=>$ret);
  1803. switch($type){
  1804. case "atom":
  1805. case "rss":
  1806. $data = api_rss_extra($a, $data, $user_info);
  1807. }
  1808. return api_apply_template("direct_messages", $type, $data);
  1809. }
  1810. api_register_func('api/direct_messages/new','api_direct_messages_new',true);
  1811. function api_direct_messages_box(&$a, $type, $box) {
  1812. if (api_user()===false) return false;
  1813. unset($_REQUEST["user_id"]);
  1814. unset($_GET["user_id"]);
  1815. unset($_REQUEST["screen_name"]);
  1816. unset($_GET["screen_name"]);
  1817. $user_info = api_get_user($a);
  1818. // params
  1819. $count = (x($_GET,'count')?$_GET['count']:20);
  1820. $page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
  1821. if ($page<0) $page=0;
  1822. $since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
  1823. $max_id = (x($_REQUEST,'max_id')?$_REQUEST['max_id']:0);
  1824. $start = $page*$count;
  1825. //$profile_url = $a->get_baseurl() . '/profile/' . $a->user['nickname'];
  1826. $profile_url = $user_info["url"];
  1827. if ($box=="sentbox") {
  1828. $sql_extra = "`mail`.`from-url`='".dbesc( $profile_url )."'";
  1829. }
  1830. elseif ($box=="conversation") {
  1831. $sql_extra = "`mail`.`parent-uri`='".dbesc( $_GET["uri"] ) ."'";
  1832. }
  1833. elseif ($box=="all") {
  1834. $sql_extra = "true";
  1835. }
  1836. elseif ($box=="inbox") {
  1837. $sql_extra = "`mail`.`from-url`!='".dbesc( $profile_url )."'";
  1838. }
  1839. if ($max_id > 0)
  1840. $sql_extra .= ' AND `mail`.`id` <= '.intval($max_id);
  1841. $r = q("SELECT `mail`.*, `contact`.`nurl` AS `contact-url` FROM `mail`,`contact` WHERE `mail`.`contact-id` = `contact`.`id` AND `mail`.`uid`=%d AND $sql_extra AND `mail`.`id` > %d ORDER BY `mail`.`id` DESC LIMIT %d,%d",
  1842. intval(api_user()),
  1843. intval($since_id),
  1844. intval($start), intval($count)
  1845. );
  1846. $ret = Array();
  1847. foreach($r as $item) {
  1848. if ($box == "inbox" || $item['from-url'] != $profile_url){
  1849. $recipient = $user_info;
  1850. $sender = api_get_user($a,normalise_link($item['contact-url']));
  1851. }
  1852. elseif ($box == "sentbox" || $item['from-url'] != $profile_url){
  1853. $recipient = api_get_user($a,normalise_link($item['contact-url']));
  1854. $sender = $user_info;
  1855. }
  1856. $ret[]=api_format_messages($item, $recipient, $sender);
  1857. }
  1858. $data = array('$messages' => $ret);
  1859. switch($type){
  1860. case "atom":
  1861. case "rss":
  1862. $data = api_rss_extra($a, $data, $user_info);
  1863. }
  1864. return api_apply_template("direct_messages", $type, $data);
  1865. }
  1866. function api_direct_messages_sentbox(&$a, $type){
  1867. return api_direct_messages_box($a, $type, "sentbox");
  1868. }
  1869. function api_direct_messages_inbox(&$a, $type){
  1870. return api_direct_messages_box($a, $type, "inbox");
  1871. }
  1872. function api_direct_messages_all(&$a, $type){
  1873. return api_direct_messages_box($a, $type, "all");
  1874. }
  1875. function api_direct_messages_conversation(&$a, $type){
  1876. return api_direct_messages_box($a, $type, "conversation");
  1877. }
  1878. api_register_func('api/direct_messages/conversation','api_direct_messages_conversation',true);
  1879. api_register_func('api/direct_messages/all','api_direct_messages_all',true);
  1880. api_register_func('api/direct_messages/sent','api_direct_messages_sentbox',true);
  1881. api_register_func('api/direct_messages','api_direct_messages_inbox',true);
  1882. function api_oauth_request_token(&$a, $type){
  1883. try{
  1884. $oauth = new FKOAuth1();
  1885. $r = $oauth->fetch_request_token(OAuthRequest::from_request());
  1886. }catch(Exception $e){
  1887. echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage()); killme();
  1888. }
  1889. echo $r;
  1890. killme();
  1891. }
  1892. function api_oauth_access_token(&$a, $type){
  1893. try{
  1894. $oauth = new FKOAuth1();
  1895. $r = $oauth->fetch_access_token(OAuthRequest::from_request());
  1896. }catch(Exception $e){
  1897. echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage()); killme();
  1898. }
  1899. echo $r;
  1900. killme();
  1901. }
  1902. api_register_func('api/oauth/request_token', 'api_oauth_request_token', false);
  1903. api_register_func('api/oauth/access_token', 'api_oauth_access_token', false);
  1904. function api_fr_photos_list(&$a,$type) {
  1905. if (api_user()===false) return false;
  1906. $r = q("select distinct `resource-id` from photo where uid = %d and album != 'Contact Photos' ",
  1907. intval(local_user())
  1908. );
  1909. if($r) {
  1910. $ret = array();
  1911. foreach($r as $rr)
  1912. $ret[] = $rr['resource-id'];
  1913. header("Content-type: application/json");
  1914. echo json_encode($ret);
  1915. }
  1916. killme();
  1917. }
  1918. function api_fr_photo_detail(&$a,$type) {
  1919. if (api_user()===false) return false;
  1920. if(! $_REQUEST['photo_id']) return false;
  1921. $scale = ((array_key_exists('scale',$_REQUEST)) ? intval($_REQUEST['scale']) : 0);
  1922. $r = q("select * from photo where uid = %d and `resource-id` = '%s' and scale = %d limit 1",
  1923. intval(local_user()),
  1924. dbesc($_REQUEST['photo_id']),
  1925. intval($scale)
  1926. );
  1927. if($r) {
  1928. header("Content-type: application/json");
  1929. $r[0]['data'] = base64_encode($r[0]['data']);
  1930. echo json_encode($r[0]);
  1931. }
  1932. killme();
  1933. }
  1934. api_register_func('api/friendica/photos/list', 'api_fr_photos_list', true);
  1935. api_register_func('api/friendica/photo', 'api_fr_photo_detail', true);
  1936. function api_share_as_retweet($a, $uid, &$item) {
  1937. $body = trim($item["body"]);
  1938. // Skip if it isn't a pure repeated messages
  1939. // Does it start with a share?
  1940. if (strpos($body, "[share") > 0)
  1941. return(false);
  1942. // Does it end with a share?
  1943. if (strlen($body) > (strrpos($body, "[/share]") + 8))
  1944. return(false);
  1945. $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
  1946. // Skip if there is no shared message in there
  1947. if ($body == $attributes)
  1948. return(false);
  1949. $author = "";
  1950. preg_match("/author='(.*?)'/ism", $attributes, $matches);
  1951. if ($matches[1] != "")
  1952. $author = html_entity_decode($matches[1],ENT_QUOTES,'UTF-8');
  1953. preg_match('/author="(.*?)"/ism', $attributes, $matches);
  1954. if ($matches[1] != "")
  1955. $author = $matches[1];
  1956. $profile = "";
  1957. preg_match("/profile='(.*?)'/ism", $attributes, $matches);
  1958. if ($matches[1] != "")
  1959. $profile = $matches[1];
  1960. preg_match('/profile="(.*?)"/ism', $attributes, $matches);
  1961. if ($matches[1] != "")
  1962. $profile = $matches[1];
  1963. $avatar = "";
  1964. preg_match("/avatar='(.*?)'/ism", $attributes, $matches);
  1965. if ($matches[1] != "")
  1966. $avatar = $matches[1];
  1967. preg_match('/avatar="(.*?)"/ism', $attributes, $matches);
  1968. if ($matches[1] != "")
  1969. $avatar = $matches[1];
  1970. $shared_body = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$2",$body);
  1971. if (($shared_body == "") OR ($profile == "") OR ($author == "") OR ($avatar == ""))
  1972. return(false);
  1973. $item["body"] = $shared_body;
  1974. $item["author-name"] = $author;
  1975. $item["author-link"] = $profile;
  1976. $item["author-avatar"] = $avatar;
  1977. return(true);
  1978. }
  1979. function api_get_nick($profile) {
  1980. /* To-Do:
  1981. - remove trailing jung from profile url
  1982. - pump.io check has to check the website
  1983. */
  1984. $nick = "";
  1985. $friendica = preg_replace("=https?://(.*)/profile/(.*)=ism", "$2", $profile);
  1986. if ($friendica != $profile)
  1987. $nick = $friendica;
  1988. if (!$nick == "") {
  1989. $diaspora = preg_replace("=https?://(.*)/u/(.*)=ism", "$2", $profile);
  1990. if ($diaspora != $profile)
  1991. $nick = $diaspora;
  1992. }
  1993. if (!$nick == "") {
  1994. $twitter = preg_replace("=https?://twitter.com/(.*)=ism", "$1", $profile);
  1995. if ($twitter != $profile)
  1996. $nick = $twitter;
  1997. }
  1998. if (!$nick == "") {
  1999. $StatusnetHost = preg_replace("=https?://(.*)/user/(.*)=ism", "$1", $profile);
  2000. if ($StatusnetHost != $profile) {
  2001. $StatusnetUser = preg_replace("=https?://(.*)/user/(.*)=ism", "$2", $profile);
  2002. if ($StatusnetUser != $profile) {
  2003. $UserData = fetch_url("http://".$StatusnetHost."/api/users/show.json?user_id=".$StatusnetUser);
  2004. $user = json_decode($UserData);
  2005. if ($user)
  2006. $nick = $user->screen_name;
  2007. }
  2008. }
  2009. }
  2010. // To-Do: look at the page if its really a pumpio site
  2011. //if (!$nick == "") {
  2012. // $pumpio = preg_replace("=https?://(.*)/(.*)/=ism", "$2", $profile."/");
  2013. // if ($pumpio != $profile)
  2014. // $nick = $pumpio;
  2015. // <div class="media" id="profile-block" data-profile-id="acct:kabniel@microca.st">
  2016. //}
  2017. if ($nick != "") {
  2018. q("UPDATE unique_contacts SET nick = '%s' WHERE url = '%s'",
  2019. dbesc($nick), dbesc(normalise_link($profile)));
  2020. return($nick);
  2021. }
  2022. return(false);
  2023. }
  2024. function api_clean_plain_items($Text) {
  2025. $include_entities = strtolower(x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:"false");
  2026. $Text = bb_CleanPictureLinks($Text);
  2027. $URLSearchString = "^\[\]";
  2028. $Text = preg_replace("/([!#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",'$1$3',$Text);
  2029. if ($include_entities == "true") {
  2030. $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",'[url=$1]$1[/url]',$Text);
  2031. }
  2032. $Text = preg_replace_callback("((.*?)\[class=(.*?)\](.*?)\[\/class\])ism","api_cleanup_share",$Text);
  2033. return($Text);
  2034. }
  2035. function api_cleanup_share($shared) {
  2036. if ($shared[2] != "type-link")
  2037. return($shared[0]);
  2038. if (!preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",$shared[3], $bookmark))
  2039. return($shared[0]);
  2040. $title = "";
  2041. $link = "";
  2042. if (isset($bookmark[2][0]))
  2043. $title = $bookmark[2][0];
  2044. if (isset($bookmark[1][0]))
  2045. $link = $bookmark[1][0];
  2046. if (strpos($shared[1],$title) !== false)
  2047. $title = "";
  2048. if (strpos($shared[1],$link) !== false)
  2049. $link = "";
  2050. $text = trim($shared[1]);
  2051. //if (strlen($text) < strlen($title))
  2052. if (($text == "") AND ($title != ""))
  2053. $text .= "\n\n".trim($title);
  2054. if ($link != "")
  2055. $text .= "\n".trim($link);
  2056. return(trim($text));
  2057. }
  2058. function api_best_nickname(&$contacts) {
  2059. $best_contact = array();
  2060. if (count($contact) == 0)
  2061. return;
  2062. foreach ($contacts AS $contact)
  2063. if ($contact["network"] == "") {
  2064. $contact["network"] = "dfrn";
  2065. $best_contact = array($contact);
  2066. }
  2067. if (sizeof($best_contact) == 0)
  2068. foreach ($contacts AS $contact)
  2069. if ($contact["network"] == "dfrn")
  2070. $best_contact = array($contact);
  2071. if (sizeof($best_contact) == 0)
  2072. foreach ($contacts AS $contact)
  2073. if ($contact["network"] == "dspr")
  2074. $best_contact = array($contact);
  2075. if (sizeof($best_contact) == 0)
  2076. foreach ($contacts AS $contact)
  2077. if ($contact["network"] == "stat")
  2078. $best_contact = array($contact);
  2079. if (sizeof($best_contact) == 0)
  2080. foreach ($contacts AS $contact)
  2081. if ($contact["network"] == "pump")
  2082. $best_contact = array($contact);
  2083. if (sizeof($best_contact) == 0)
  2084. foreach ($contacts AS $contact)
  2085. if ($contact["network"] == "twit")
  2086. $best_contact = array($contact);
  2087. if (sizeof($best_contact) == 1)
  2088. $contacts = $best_contact;
  2089. else
  2090. $contacts = array($contacts[0]);
  2091. }
  2092. /*
  2093. Not implemented by now:
  2094. favorites
  2095. favorites/create
  2096. favorites/destroy
  2097. statuses/retweets_of_me
  2098. friendships/create
  2099. friendships/destroy
  2100. friendships/exists
  2101. friendships/show
  2102. account/update_location
  2103. account/update_profile_background_image
  2104. account/update_profile_image
  2105. blocks/create
  2106. blocks/destroy
  2107. Not implemented in status.net:
  2108. statuses/retweeted_to_me
  2109. statuses/retweeted_by_me
  2110. direct_messages/destroy
  2111. account/end_session
  2112. account/update_delivery_device
  2113. notifications/follow
  2114. notifications/leave
  2115. blocks/exists
  2116. blocks/blocking
  2117. lists
  2118. */