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

802 lines
22KB

  1. <?php
  2. /**
  3. * @file include/acl_selectors.php
  4. */
  5. use Friendica\App;
  6. use Friendica\Core\Config;
  7. use Friendica\Database\DBM;
  8. require_once "include/contact_selectors.php";
  9. require_once "include/contact_widgets.php";
  10. require_once "include/DirSearch.php";
  11. require_once "include/features.php";
  12. require_once "mod/proxy.php";
  13. /**
  14. * @package acl_selectors
  15. */
  16. function group_select($selname,$selclass,$preselected = false,$size = 4) {
  17. $a = get_app();
  18. $o = '';
  19. $o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"$size\" >\r\n";
  20. $r = q("SELECT `id`, `name` FROM `group` WHERE NOT `deleted` AND `uid` = %d ORDER BY `name` ASC",
  21. intval(local_user())
  22. );
  23. $arr = array('group' => $r, 'entry' => $o);
  24. // e.g. 'network_pre_group_deny', 'profile_pre_group_allow'
  25. call_hooks($a->module . '_pre_' . $selname, $arr);
  26. if (DBM::is_result($r)) {
  27. foreach ($r as $rr) {
  28. if ((is_array($preselected)) && in_array($rr['id'], $preselected)) {
  29. $selected = " selected=\"selected\" ";
  30. } else {
  31. $selected = '';
  32. }
  33. $trimmed = mb_substr($rr['name'],0,12);
  34. $o .= "<option value=\"{$rr['id']}\" $selected title=\"{$rr['name']}\" >$trimmed</option>\r\n";
  35. }
  36. }
  37. $o .= "</select>\r\n";
  38. call_hooks($a->module . '_post_' . $selname, $o);
  39. return $o;
  40. }
  41. /// @TODO after an optional parameter, no mandadory parameter can follow
  42. /// @TODO find proper type-hints
  43. function contact_selector($selname, $selclass, $preselected = false, $options) {
  44. $a = get_app();
  45. $mutual = false;
  46. $networks = null;
  47. $single = false;
  48. $exclude = false;
  49. $size = 4;
  50. if (is_array($options)) {
  51. if (x($options, 'size'))
  52. $size = $options['size'];
  53. if (x($options, 'mutual_friends')) {
  54. $mutual = true;
  55. }
  56. if (x($options, 'single')) {
  57. $single = true;
  58. }
  59. if (x($options, 'multiple')) {
  60. $single = false;
  61. }
  62. if (x($options, 'exclude')) {
  63. $exclude = $options['exclude'];
  64. }
  65. if (x($options, 'networks')) {
  66. switch ($options['networks']) {
  67. case 'DFRN_ONLY':
  68. $networks = array(NETWORK_DFRN);
  69. break;
  70. case 'PRIVATE':
  71. if (is_array($a->user) && $a->user['prvnets']) {
  72. $networks = array(NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA);
  73. } else {
  74. $networks = array(NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA);
  75. }
  76. break;
  77. case 'TWO_WAY':
  78. if (is_array($a->user) && $a->user['prvnets']) {
  79. $networks = array(NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA);
  80. } else {
  81. $networks = array(NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA, NETWORK_OSTATUS);
  82. }
  83. break;
  84. default: /// @TODO Maybe log this call?
  85. break;
  86. }
  87. }
  88. }
  89. $x = array('options' => $options, 'size' => $size, 'single' => $single, 'mutual' => $mutual, 'exclude' => $exclude, 'networks' => $networks);
  90. call_hooks('contact_select_options', $x);
  91. $o = '';
  92. $sql_extra = '';
  93. if (x($x, 'mutual')) {
  94. $sql_extra .= sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND));
  95. }
  96. if (x($x, 'exclude')) {
  97. $sql_extra .= sprintf(" AND `id` != %d ", intval($x['exclude']));
  98. }
  99. if (is_array($x['networks']) && count($x['networks'])) {
  100. /// @TODO rewrite to foreach()
  101. for ($y = 0; $y < count($x['networks']) ; $y ++) {
  102. $x['networks'][$y] = "'" . dbesc($x['networks'][$y]) . "'";
  103. }
  104. $str_nets = implode(',', $x['networks']);
  105. $sql_extra .= " AND `network` IN ( $str_nets ) ";
  106. }
  107. $tabindex = (x($options, 'tabindex') ? "tabindex=\"" . $options["tabindex"] . "\"" : "");
  108. if ($x['single']) {
  109. $o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"" . $x['size'] . "\" $tabindex >\r\n";
  110. } else {
  111. $o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"" . $x['size'] . "$\" $tabindex >\r\n";
  112. }
  113. $r = q("SELECT `id`, `name`, `url`, `network` FROM `contact`
  114. WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
  115. $sql_extra
  116. ORDER BY `name` ASC ",
  117. intval(local_user())
  118. );
  119. $arr = array('contact' => $r, 'entry' => $o);
  120. // e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow'
  121. call_hooks($a->module . '_pre_' . $selname, $arr);
  122. if (DBM::is_result($r)) {
  123. foreach ($r as $rr) {
  124. if ((is_array($preselected)) && in_array($rr['id'], $preselected)) {
  125. $selected = " selected=\"selected\" ";
  126. } else {
  127. $selected = '';
  128. }
  129. $trimmed = mb_substr($rr['name'],0,20);
  130. $o .= "<option value=\"{$rr['id']}\" $selected title=\"{$rr['name']}|{$rr['url']}\" >$trimmed</option>\r\n";
  131. }
  132. }
  133. $o .= "</select>\r\n";
  134. call_hooks($a->module . '_post_' . $selname, $o);
  135. return $o;
  136. }
  137. function contact_select($selname, $selclass, $preselected = false, $size = 4, $privmail = false, $celeb = false, $privatenet = false, $tabindex = null) {
  138. require_once "include/bbcode.php";
  139. $a = get_app();
  140. $o = '';
  141. // When used for private messages, we limit correspondence to mutual DFRN/Friendica friends and the selector
  142. // to one recipient. By default our selector allows multiple selects amongst all contacts.
  143. $sql_extra = '';
  144. if ($privmail || $celeb) {
  145. $sql_extra .= sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND));
  146. }
  147. if ($privmail) {
  148. $sql_extra .= sprintf(" AND `network` IN ('%s' , '%s') ",
  149. NETWORK_DFRN, NETWORK_DIASPORA);
  150. } elseif ($privatenet) {
  151. $sql_extra .= sprintf(" AND `network` IN ('%s' , '%s', '%s', '%s') ",
  152. NETWORK_DFRN, NETWORK_MAIL, NETWORK_FACEBOOK, NETWORK_DIASPORA);
  153. }
  154. $tabindex = ($tabindex > 0 ? "tabindex=\"$tabindex\"" : "");
  155. if ($privmail && $preselected) {
  156. $sql_extra .= " AND `id` IN (".implode(",", $preselected).")";
  157. $hidepreselected = ' style="display: none;"';
  158. } else {
  159. $hidepreselected = "";
  160. }
  161. if ($privmail) {
  162. $o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\" $tabindex $hidepreselected>\r\n";
  163. } else {
  164. $o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"$size\" $tabindex >\r\n";
  165. }
  166. $r = q("SELECT `id`, `name`, `url`, `network` FROM `contact`
  167. WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
  168. $sql_extra
  169. ORDER BY `name` ASC ",
  170. intval(local_user())
  171. );
  172. $arr = array('contact' => $r, 'entry' => $o);
  173. // e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow'
  174. call_hooks($a->module . '_pre_' . $selname, $arr);
  175. $receiverlist = array();
  176. if (DBM::is_result($r)) {
  177. foreach ($r as $rr) {
  178. if ((is_array($preselected)) && in_array($rr['id'], $preselected)) {
  179. $selected = " selected=\"selected\" ";
  180. } else {
  181. $selected = '';
  182. }
  183. if ($privmail) {
  184. $trimmed = GetProfileUsername($rr['url'], $rr['name'], false);
  185. } else {
  186. $trimmed = mb_substr($rr['name'],0,20);
  187. }
  188. $receiverlist[] = $trimmed;
  189. $o .= "<option value=\"{$rr['id']}\" $selected title=\"{$rr['name']}|{$rr['url']}\" >$trimmed</option>\r\n";
  190. }
  191. }
  192. $o .= "</select>\r\n";
  193. if ($privmail && $preselected) {
  194. $o .= implode(", ", $receiverlist);
  195. }
  196. call_hooks($a->module . '_post_' . $selname, $o);
  197. return $o;
  198. }
  199. function fixacl(&$item) {
  200. $item = intval(str_replace(array('<', '>'), array('', ''), $item));
  201. }
  202. function prune_deadguys($arr) {
  203. if (! $arr) {
  204. return $arr;
  205. }
  206. $str = dbesc(implode(',', $arr));
  207. $r = q("SELECT `id` FROM `contact` WHERE `id` IN ( " . $str . ") AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0 ");
  208. if (DBM::is_result($r)) {
  209. $ret = array();
  210. foreach ($r as $rr) {
  211. $ret[] = intval($rr['id']);
  212. }
  213. return $ret;
  214. }
  215. return array();
  216. }
  217. function get_acl_permissions($user = null) {
  218. $allow_cid = $allow_gid = $deny_cid = $deny_gid = false;
  219. if (is_array($user)) {
  220. $allow_cid = ((strlen($user['allow_cid']))
  221. ? explode('><', $user['allow_cid']) : array() );
  222. $allow_gid = ((strlen($user['allow_gid']))
  223. ? explode('><', $user['allow_gid']) : array() );
  224. $deny_cid = ((strlen($user['deny_cid']))
  225. ? explode('><', $user['deny_cid']) : array() );
  226. $deny_gid = ((strlen($user['deny_gid']))
  227. ? explode('><', $user['deny_gid']) : array() );
  228. array_walk($allow_cid,'fixacl');
  229. array_walk($allow_gid,'fixacl');
  230. array_walk($deny_cid,'fixacl');
  231. array_walk($deny_gid,'fixacl');
  232. }
  233. $allow_cid = prune_deadguys($allow_cid);
  234. return array(
  235. 'allow_cid' => $allow_cid,
  236. 'allow_gid' => $allow_gid,
  237. 'deny_cid' => $deny_cid,
  238. 'deny_gid' => $deny_gid,
  239. );
  240. }
  241. function populate_acl($user = null, $show_jotnets = false) {
  242. $perms = get_acl_permissions($user);
  243. $jotnets = '';
  244. if ($show_jotnets) {
  245. $mail_disabled = ((function_exists('imap_open') && (! Config::get('system','imap_disabled'))) ? 0 : 1);
  246. $mail_enabled = false;
  247. $pubmail_enabled = false;
  248. if (! $mail_disabled) {
  249. $r = q("SELECT `pubmail` FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1",
  250. intval(local_user())
  251. );
  252. if (DBM::is_result($r)) {
  253. $mail_enabled = true;
  254. if (intval($r[0]['pubmail'])) {
  255. $pubmail_enabled = true;
  256. }
  257. }
  258. }
  259. if (!$user['hidewall']) {
  260. if ($mail_enabled) {
  261. $selected = (($pubmail_enabled) ? ' checked="checked" ' : '');
  262. $jotnets .= '<div class="profile-jot-net"><input type="checkbox" name="pubmail_enable"' . $selected . ' value="1" /> ' . t("Post to Email") . '</div>';
  263. }
  264. call_hooks('jot_networks', $jotnets);
  265. } else {
  266. $jotnets .= sprintf(t('Connectors disabled, since "%s" is enabled.'),
  267. t('Hide your profile details from unknown viewers?'));
  268. }
  269. }
  270. $tpl = get_markup_template("acl_selector.tpl");
  271. $o = replace_macros($tpl, array(
  272. '$showall'=> t("Visible to everybody"),
  273. '$show' => t("show"),
  274. '$hide' => t("don't show"),
  275. '$allowcid' => json_encode($perms['allow_cid']),
  276. '$allowgid' => json_encode($perms['allow_gid']),
  277. '$denycid' => json_encode($perms['deny_cid']),
  278. '$denygid' => json_encode($perms['deny_gid']),
  279. '$networks' => $show_jotnets,
  280. '$emailcc' => t('CC: email addresses'),
  281. '$emtitle' => t('Example: bob@example.com, mary@example.com'),
  282. '$jotnets' => $jotnets,
  283. '$aclModalTitle' => t('Permissions'),
  284. '$aclModalDismiss' => t('Close'),
  285. '$features' => array(
  286. 'aclautomention' => (feature_enabled($user['uid'], "aclautomention") ? "true" : "false")
  287. ),
  288. ));
  289. return $o;
  290. }
  291. function construct_acl_data(App $a, $user) {
  292. // This function is now deactivated. It seems as if the generated data isn't used anywhere.
  293. /// @todo Remove this function and all function calls before releasing Friendica 3.5.3
  294. return;
  295. // Get group and contact information for html ACL selector
  296. $acl_data = acl_lookup($a, 'html');
  297. $user_defaults = get_acl_permissions($user);
  298. if ($acl_data['groups']) {
  299. foreach ($acl_data['groups'] as $key => $group) {
  300. // Add a "selected" flag to groups that are posted to by default
  301. if ($user_defaults['allow_gid'] &&
  302. in_array($group['id'], $user_defaults['allow_gid']) && !in_array($group['id'], $user_defaults['deny_gid']) ) {
  303. $acl_data['groups'][$key]['selected'] = 1;
  304. } else {
  305. $acl_data['groups'][$key]['selected'] = 0;
  306. }
  307. }
  308. }
  309. if ($acl_data['contacts']) {
  310. foreach ($acl_data['contacts'] as $key => $contact) {
  311. // Add a "selected" flag to groups that are posted to by default
  312. if ($user_defaults['allow_cid'] &&
  313. in_array($contact['id'], $user_defaults['allow_cid']) && !in_array($contact['id'], $user_defaults['deny_cid']) ) {
  314. $acl_data['contacts'][$key]['selected'] = 1;
  315. } else {
  316. $acl_data['contacts'][$key]['selected'] = 0;
  317. }
  318. }
  319. }
  320. return $acl_data;
  321. }
  322. function acl_lookup(App $a, $out_type = 'json') {
  323. if (!local_user()) {
  324. return '';
  325. }
  326. $start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0);
  327. $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
  328. $search = (x($_REQUEST,'search') ? $_REQUEST['search'] : "");
  329. $type = (x($_REQUEST,'type') ? $_REQUEST['type'] : "");
  330. $mode = (x($_REQUEST,'smode') ? $_REQUEST['smode'] : "");
  331. $conv_id = (x($_REQUEST,'conversation') ? $_REQUEST['conversation'] : null);
  332. // For use with jquery.textcomplete for private mail completion
  333. if (x($_REQUEST, 'query') && strlen($_REQUEST['query'])) {
  334. if (! $type) {
  335. $type = 'm';
  336. }
  337. $search = $_REQUEST['query'];
  338. }
  339. logger("Searching for ".$search." - type ".$type, LOGGER_DEBUG);
  340. if ($search != "") {
  341. $sql_extra = "AND `name` LIKE '%%".dbesc($search)."%%'";
  342. $sql_extra2 = "AND (`attag` LIKE '%%".dbesc($search)."%%' OR `name` LIKE '%%".dbesc($search)."%%' OR `nick` LIKE '%%".dbesc($search)."%%')";
  343. } else {
  344. /// @TODO Avoid these needless else blocks by putting variable-initialization atop of if()
  345. $sql_extra = $sql_extra2 = "";
  346. }
  347. // count groups and contacts
  348. if ($type == '' || $type == 'g') {
  349. $r = q("SELECT COUNT(*) AS g FROM `group` WHERE `deleted` = 0 AND `uid` = %d $sql_extra",
  350. intval(local_user())
  351. );
  352. $group_count = (int)$r[0]['g'];
  353. } else {
  354. $group_count = 0;
  355. }
  356. $sql_extra2 .= " ".unavailable_networks();
  357. if ($type == '' || $type == 'c') {
  358. // autocomplete for editor mentions
  359. $r = q("SELECT COUNT(*) AS c FROM `contact`
  360. WHERE `uid` = %d AND NOT `self`
  361. AND NOT `blocked` AND NOT `pending` AND NOT `archive`
  362. AND `success_update` >= `failure_update`
  363. AND `notify` != '' $sql_extra2" ,
  364. intval(local_user())
  365. );
  366. $contact_count = (int)$r[0]['c'];
  367. } elseif ($type == 'f') {
  368. // autocomplete for editor mentions of forums
  369. $r = q("SELECT COUNT(*) AS c FROM `contact`
  370. WHERE `uid` = %d AND NOT `self`
  371. AND NOT `blocked` AND NOT `pending` AND NOT `archive`
  372. AND (`forum` OR `prv`)
  373. AND `success_update` >= `failure_update`
  374. AND `notify` != '' $sql_extra2" ,
  375. intval(local_user())
  376. );
  377. $contact_count = (int)$r[0]['c'];
  378. } elseif ($type == 'm') {
  379. // autocomplete for Private Messages
  380. $r = q("SELECT COUNT(*) AS c FROM `contact`
  381. WHERE `uid` = %d AND NOT `self`
  382. AND NOT `blocked` AND NOT `pending` AND NOT `archive`
  383. AND `success_update` >= `failure_update`
  384. AND `network` IN ('%s','%s','%s') $sql_extra2" ,
  385. intval(local_user()),
  386. dbesc(NETWORK_DFRN),
  387. dbesc(NETWORK_ZOT),
  388. dbesc(NETWORK_DIASPORA)
  389. );
  390. $contact_count = (int)$r[0]['c'];
  391. } elseif ($type == 'a') {
  392. // autocomplete for Contacts
  393. $r = q("SELECT COUNT(*) AS c FROM `contact`
  394. WHERE `uid` = %d AND NOT `self`
  395. AND NOT `pending` $sql_extra2" ,
  396. intval(local_user())
  397. );
  398. $contact_count = (int)$r[0]['c'];
  399. } else {
  400. $contact_count = 0;
  401. }
  402. $tot = $group_count+$contact_count;
  403. $groups = array();
  404. $contacts = array();
  405. if ($type == '' || $type == 'g') {
  406. /// @todo We should cache this query.
  407. // This can be done when we can delete cache entries via wildcard
  408. $r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') AS uids
  409. FROM `group`
  410. INNER JOIN `group_member` ON `group_member`.`gid`=`group`.`id` AND `group_member`.`uid` = `group`.`uid`
  411. WHERE NOT `group`.`deleted` AND `group`.`uid` = %d
  412. $sql_extra
  413. GROUP BY `group`.`name`, `group`.`id`
  414. ORDER BY `group`.`name`
  415. LIMIT %d,%d",
  416. intval(local_user()),
  417. intval($start),
  418. intval($count)
  419. );
  420. foreach ($r as $g) {
  421. // logger('acl: group: ' . $g['name'] . ' members: ' . $g['uids']);
  422. $groups[] = array(
  423. "type" => "g",
  424. "photo" => "images/twopeople.png",
  425. "name" => htmlentities($g['name']),
  426. "id" => intval($g['id']),
  427. "uids" => array_map("intval", explode(",",$g['uids'])),
  428. "link" => '',
  429. "forum" => '0'
  430. );
  431. }
  432. if ((count($groups) > 0) && ($search == "")) {
  433. $groups[] = array("separator" => true);
  434. }
  435. }
  436. if ($type == '') {
  437. $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv`, (`prv` OR `forum`) AS `frm` FROM `contact`
  438. WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
  439. AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s', '%s'))
  440. $sql_extra2
  441. ORDER BY `name` ASC ",
  442. intval(local_user()),
  443. dbesc(NETWORK_OSTATUS), dbesc(NETWORK_STATUSNET)
  444. );
  445. } elseif ($type == 'c') {
  446. $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
  447. WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
  448. AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
  449. $sql_extra2
  450. ORDER BY `name` ASC ",
  451. intval(local_user()),
  452. dbesc(NETWORK_STATUSNET)
  453. );
  454. } elseif ($type == 'f') {
  455. $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
  456. WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
  457. AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
  458. AND (`forum` OR `prv`)
  459. $sql_extra2
  460. ORDER BY `name` ASC ",
  461. intval(local_user()),
  462. dbesc(NETWORK_STATUSNET)
  463. );
  464. } elseif ($type == 'm') {
  465. $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact`
  466. WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
  467. AND `success_update` >= `failure_update` AND `network` IN ('%s','%s','%s')
  468. $sql_extra2
  469. ORDER BY `name` ASC ",
  470. intval(local_user()),
  471. dbesc(NETWORK_DFRN),
  472. dbesc(NETWORK_ZOT),
  473. dbesc(NETWORK_DIASPORA)
  474. );
  475. } elseif ($type == 'a') {
  476. $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
  477. WHERE `uid` = %d AND `pending` = 0 AND `success_update` >= `failure_update`
  478. $sql_extra2
  479. ORDER BY `name` ASC ",
  480. intval(local_user())
  481. );
  482. } elseif ($type == 'x') {
  483. // autocomplete for global contact search (e.g. navbar search)
  484. $r = navbar_complete($a);
  485. $contacts = array();
  486. if ($r) {
  487. foreach ($r as $g) {
  488. $contacts[] = array(
  489. 'photo' => proxy_url($g['photo'], false, PROXY_SIZE_MICRO),
  490. 'name' => $g['name'],
  491. 'nick' => (x($g['addr']) ? $g['addr'] : $g['url']),
  492. 'network' => $g['network'],
  493. 'link' => $g['url'],
  494. 'forum' => (x($g['community']) ? 1 : 0),
  495. );
  496. }
  497. }
  498. $o = array(
  499. 'start' => $start,
  500. 'count' => $count,
  501. 'items' => $contacts,
  502. );
  503. echo json_encode($o);
  504. killme();
  505. } else {
  506. $r = array();
  507. }
  508. if (DBM::is_result($r)) {
  509. $forums = array();
  510. foreach ($r as $g) {
  511. $entry = array(
  512. 'type' => 'c',
  513. 'photo' => proxy_url($g['micro'], false, PROXY_SIZE_MICRO),
  514. 'name' => htmlentities($g['name']),
  515. 'id' => intval($g['id']),
  516. 'network' => $g['network'],
  517. 'link' => $g['url'],
  518. 'nick' => htmlentities(($g['attag']) ? $g['attag'] : $g['nick']),
  519. 'addr' => htmlentities(($g['addr']) ? $g['addr'] : $g['url']),
  520. 'forum' => ((x($g, 'forum') || x($g, 'prv')) ? 1 : 0),
  521. );
  522. if ($entry['forum']) {
  523. $forums[] = $entry;
  524. } else {
  525. $contacts[] = $entry;
  526. }
  527. }
  528. if (count($forums) > 0) {
  529. if ($search == "") {
  530. $forums[] = array("separator" => true);
  531. }
  532. $contacts = array_merge($forums, $contacts);
  533. }
  534. }
  535. $items = array_merge($groups, $contacts);
  536. if ($conv_id) {
  537. /*
  538. * if $conv_id is set, get unknown contacts in thread
  539. * but first get known contacts url to filter them out
  540. */
  541. $known_contacts = array_map(
  542. function ($i) {
  543. return dbesc($i['link']);
  544. }
  545. , $contacts);
  546. $unknown_contacts = array();
  547. $r = q("SELECT `author-link`
  548. FROM `item` WHERE `parent` = %d
  549. AND (`author-name` LIKE '%%%s%%' OR `author-link` LIKE '%%%s%%')
  550. AND `author-link` NOT IN ('%s')
  551. GROUP BY `author-link`, `author-avatar`, `author-name`
  552. ORDER BY `author-name` ASC
  553. ",
  554. intval($conv_id),
  555. dbesc($search),
  556. dbesc($search),
  557. implode("', '", $known_contacts)
  558. );
  559. if (DBM::is_result($r)) {
  560. foreach ($r as $row) {
  561. $contact = get_contact_details_by_url($row['author-link']);
  562. if (count($contact) > 0) {
  563. $unknown_contacts[] = array(
  564. 'type' => 'c',
  565. 'photo' => proxy_url($contact['micro'], false, PROXY_SIZE_MICRO),
  566. 'name' => htmlentities($contact['name']),
  567. 'id' => intval($contact['cid']),
  568. 'network' => $contact['network'],
  569. 'link' => $contact['url'],
  570. 'nick' => htmlentities($contact['nick'] ? : $contact['addr']),
  571. 'addr' => htmlentities(($contact['addr']) ? $contact['addr'] : $contact['url']),
  572. 'forum' => $contact['forum']
  573. );
  574. }
  575. }
  576. }
  577. $items = array_merge($items, $unknown_contacts);
  578. $tot += count($unknown_contacts);
  579. }
  580. $results = array(
  581. 'tot' => $tot,
  582. 'start' => $start,
  583. 'count' => $count,
  584. 'groups' => $groups,
  585. 'contacts' => $contacts,
  586. 'items' => $items,
  587. 'type' => $type,
  588. 'search' => $search,
  589. );
  590. call_hooks('acl_lookup_end', $results);
  591. if ($out_type === 'html') {
  592. $o = array(
  593. 'tot' => $results['tot'],
  594. 'start' => $results['start'],
  595. 'count' => $results['count'],
  596. 'groups' => $results['groups'],
  597. 'contacts' => $results['contacts'],
  598. );
  599. return $o;
  600. }
  601. $o = array(
  602. 'tot' => $results['tot'],
  603. 'start' => $results['start'],
  604. 'count' => $results['count'],
  605. 'items' => $results['items'],
  606. );
  607. echo json_encode($o);
  608. killme();
  609. }
  610. /**
  611. * @brief Searching for global contacts for autocompletion
  612. *
  613. * @param App $a
  614. * @return array with the search results
  615. */
  616. function navbar_complete(App $a) {
  617. // logger('navbar_complete');
  618. if ((Config::get('system','block_public')) && (! local_user()) && (! remote_user())) {
  619. return;
  620. }
  621. // check if searching in the local global contact table is enabled
  622. $localsearch = Config::get('system','poco_local_search');
  623. $search = $prefix.notags(trim($_REQUEST['search']));
  624. $mode = $_REQUEST['smode'];
  625. // don't search if search term has less than 2 characters
  626. if (! $search || mb_strlen($search) < 2) {
  627. return array();
  628. }
  629. if (substr($search,0,1) === '@') {
  630. $search = substr($search,1);
  631. }
  632. if ($localsearch) {
  633. $x = DirSearch::global_search_by_name($search, $mode);
  634. return $x;
  635. }
  636. if (! $localsearch) {
  637. $p = (($a->pager['page'] != 1) ? '&p=' . $a->pager['page'] : '');
  638. $x = z_fetch_url(get_server().'/lsearch?f=' . $p . '&search=' . urlencode($search));
  639. if ($x['success']) {
  640. $t = 0;
  641. $j = json_decode($x['body'],true);
  642. if ($j && $j['results']) {
  643. return $j['results'];
  644. }
  645. }
  646. }
  647. /// @TODO Not needed here?
  648. return;
  649. }