function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) { $where = ''; $limit = ''; $t0 = dba_timer(); if ($numitems) { $limit = " LIMIT " . intval($numitems) . " OFFSET " . intval($start); } if ($mailbox !== '') { $x = q("select channel_hash from channel where channel_id = %d limit 1", intval($uid)); if (!$x) { return array(); } $channel_hash = dbesc($x[0]['channel_hash']); $local_channel = intval(local_channel()); switch ($mailbox) { case 'inbox': $sql = "SELECT * FROM mail WHERE channel_id = {$local_channel} AND from_xchan != '{$channel_hash}' ORDER BY created DESC {$limit}"; break; case 'outbox': $sql = "SELECT * FROM mail WHERE channel_id = {$local_channel} AND from_xchan = '{$channel_hash}' ORDER BY created DESC {$limit}"; break; case 'combined': $sql = "SELECT * FROM ( SELECT * FROM mail WHERE channel_id = {$local_channel} ORDER BY created DESC {$limit} ) AS temp_table GROUP BY parent_mid ORDER BY created DESC"; break; } } $r = q($sql); if (!$r) { return array(); } $chans = array(); foreach ($r as $rr) { $s = "'" . dbesc(trim($rr['from_xchan'])) . "'"; if (!in_array($s, $chans)) { $chans[] = $s; } $s = "'" . dbesc(trim($rr['to_xchan'])) . "'"; if (!in_array($s, $chans)) { $chans[] = $s; } } $c = q("select * from xchan where xchan_hash in (" . implode(',', $chans) . ")"); foreach ($r as $k => $rr) { $r[$k]['from'] = find_xchan_in_array($rr['from_xchan'], $c); $r[$k]['to'] = find_xchan_in_array($rr['to_xchan'], $c); $r[$k]['seen'] = intval($rr['mail_seen']); if (intval($r[$k]['mail_obscured'])) { if ($r[$k]['title']) { $r[$k]['title'] = base64url_decode(str_rot47($r[$k]['title'])); } if ($r[$k]['body']) { $r[$k]['body'] = base64url_decode(str_rot47($r[$k]['body'])); } } } return $r; }
/** * @brief do several updates when pinged. * * This function does several tasks. Whenever called it checks for new messages, * introductions, notifications, etc. and returns a json with the results. * * @param App &$a * @result JSON */ function ping_init(&$a) { $result = array(); $notifs = array(); $result['notify'] = 0; $result['home'] = 0; $result['network'] = 0; $result['intros'] = 0; $result['mail'] = 0; $result['register'] = 0; $result['events'] = 0; $result['events_today'] = 0; $result['birthdays'] = 0; $result['birthdays_today'] = 0; $result['all_events'] = 0; $result['all_events_today'] = 0; $result['notice'] = array(); $result['info'] = array(); $t0 = dba_timer(); header("content-type: application/json"); /** * If you have several windows open to this site and switch to a different channel * in one of them, the others may get into a confused state showing you a page or options * on that page which were only valid under the old identity. You session has changed. * Therefore we send a notification of this fact back to the browser where it is picked up * in javascript and which reloads the page it is on so that it is valid under the context * of the now current channel. */ $result['invalid'] = intval($_GET['uid']) && intval($_GET['uid']) != local_user() ? 1 : 0; /** * Send all system messages (alerts) to the browser. * Some are marked as informational and some represent * errors or serious notifications. These typically * will popup on the current page (no matter what page it is) */ if (x($_SESSION, 'sysmsg')) { foreach ($_SESSION['sysmsg'] as $m) { $result['notice'][] = array('message' => $m); } unset($_SESSION['sysmsg']); } if (x($_SESSION, 'sysmsg_info')) { foreach ($_SESSION['sysmsg_info'] as $m) { $result['info'][] = array('message' => $m); } unset($_SESSION['sysmsg_info']); } if ($a->install) { echo json_encode($result); killme(); } /** * Update chat presence indication (if applicable) */ if (get_observer_hash() && !$result['invalid']) { $r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1", dbesc(get_observer_hash()), dbesc($_SERVER['REMOTE_ADDR'])); $basic_presence = false; if ($r) { $basic_presence = true; q("update chatpresence set cp_last = '%s' where cp_id = %d limit 1", dbesc(datetime_convert()), intval($r[0]['cp_id'])); } if (!$basic_presence) { q("insert into chatpresence ( cp_xchan, cp_last, cp_status, cp_client)\n\t\t\t\tvalues( '%s', '%s', '%s', '%s' ) ", dbesc(get_observer_hash()), dbesc(datetime_convert()), dbesc('online'), dbesc($_SERVER['REMOTE_ADDR'])); } } /** * Chatpresence continued... if somebody hasn't pinged recently, they've most likely left the page * and shouldn't count as online anymore. We allow an expection for bots. */ q("delete from chatpresence where cp_last < UTC_TIMESTAMP() - INTERVAL 3 MINUTE and cp_client != 'auto' "); if (!local_user() || $result['invalid']) { echo json_encode($result); killme(); } /** * Everything following is only permitted under the context of a locally authenticated site member. */ /** * Handle "mark all xyz notifications read" requests. */ // mark all items read if (x($_REQUEST, 'markRead') && local_user()) { switch ($_REQUEST['markRead']) { case 'network': $r = q("update item set item_flags = ( item_flags ^ %d ) where (item_flags & %d) and uid = %d", intval(ITEM_UNSEEN), intval(ITEM_UNSEEN), intval(local_user())); break; case 'home': $r = q("update item set item_flags = ( item_flags ^ %d ) where (item_flags & %d) and (item_flags & %d) and uid = %d", intval(ITEM_UNSEEN), intval(ITEM_UNSEEN), intval(ITEM_WALL), intval(local_user())); break; case 'messages': $r = q("update mail set mail_flags = ( mail_flags ^ %d ) where channel_id = %d and not (mail_flags & %d)", intval(MAIL_SEEN), intval(local_user()), intval(MAIL_SEEN)); break; case 'all_events': $r = q("update event set `ignore` = 1 where `ignore` = 0 and uid = %d", intval(local_user())); break; case 'notify': $r = q("update notify set seen = 1 where uid = %d", intval(local_user())); break; default: break; } } /** * URL ping/something will return detail for "something", e.g. a json list with which to populate a notification * dropdown menu. */ if (argc() > 1 && argv(1) === 'notify') { $t = q("select count(*) as total from notify where uid = %d and seen = 0", intval(local_user())); if ($t && intval($t[0]['total']) > 49) { $z = q("select * from notify where uid = %d\n\t\t\t\tand seen = 0 order by date desc limit 0, 50", intval(local_user())); } else { $z1 = q("select * from notify where uid = %d\n\t\t\t\tand seen = 0 order by date desc limit 0, 50", intval(local_user())); $z2 = q("select * from notify where uid = %d\n\t\t\t\tand seen = 1 order by date desc limit 0, %d", intval(local_user()), intval(50 - intval($t[0]['total']))); $z = array_merge($z1, $z2); } if (count($z)) { foreach ($z as $zz) { $notifs[] = array('notify_link' => $a->get_baseurl() . '/notify/view/' . $zz['id'], 'name' => '', 'url' => $zz['url'], 'photo' => $zz['photo'], 'when' => relative_date($zz['date']), 'class' => $zz['seen'] ? 'notify-seen' : 'notify-unseen', 'message' => strip_tags(bbcode($zz['msg']))); } } echo json_encode(array('notify' => $notifs)); killme(); } if (argc() > 1 && argv(1) === 'messages') { $channel = $a->get_channel(); $t = q("select mail.*, xchan.* from mail left join xchan on xchan_hash = from_xchan \n\t\t\twhere channel_id = %d and not ( mail_flags & %d ) and not (mail_flags & %d ) \n\t\t\tand from_xchan != '%s' order by created desc limit 0,50", intval(local_user()), intval(MAIL_SEEN), intval(MAIL_DELETED), dbesc($channel['channel_hash'])); if ($t) { foreach ($t as $zz) { $notifs[] = array('notify_link' => $a->get_baseurl() . '/mail/' . $zz['id'], 'name' => $zz['xchan_name'], 'url' => $zz['xchan_url'], 'photo' => $zz['xchan_photo_s'], 'when' => relative_date($zz['created']), 'class' => $zz['mail_flags'] & MAIL_SEEN ? 'notify-seen' : 'notify-unseen', 'message' => t('sent you a private message')); } } echo json_encode(array('notify' => $notifs)); killme(); } if (argc() > 1 && (argv(1) === 'network' || argv(1) === 'home')) { $result = array(); $r = q("SELECT * FROM item\n\t\t\tWHERE item_restrict = %d and ( item_flags & %d ) and uid = %d", intval(ITEM_VISIBLE), intval(ITEM_UNSEEN), intval(local_user())); if ($r) { xchan_query($r); foreach ($r as $item) { if (argv(1) === 'home' && !($item['item_flags'] & ITEM_WALL)) { continue; } $result[] = format_notification($item); } } logger('ping (network||home): ' . print_r($result, true), LOGGER_DATA); echo json_encode(array('notify' => $result)); killme(); } if (argc() > 1 && argv(1) === 'intros') { $result = array(); $r = q("SELECT * FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and (abook_flags & %d) and not ((abook_flags & %d) or (xchan_flags & %d))", intval(local_user()), intval(ABOOK_FLAG_PENDING), intval(ABOOK_FLAG_SELF | ABOOK_FLAG_IGNORED), intval(XCHAN_FLAGS_DELETED | XCHAN_FLAGS_ORPHAN)); if ($r) { foreach ($r as $rr) { $result[] = array('notify_link' => $a->get_baseurl() . '/connedit/' . $rr['abook_id'], 'name' => $rr['xchan_name'], 'url' => $rr['xchan_url'], 'photo' => $rr['xchan_photo_s'], 'when' => relative_date($rr['abook_created']), 'class' => 'notify-unseen', 'message' => t('added your channel')); } } logger('ping (intros): ' . print_r($result, true), LOGGER_DATA); echo json_encode(array('notify' => $result)); killme(); } if (argc() > 1 && argv(1) === 'all_events') { $bd_format = t('g A l F d'); // 8 AM Friday January 18 $result = array(); $r = q("SELECT * FROM event left join xchan on event_xchan = xchan_hash\n\t\t\tWHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0\n\t\t\tORDER BY `start` DESC ", intval(local_user()), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + 7 days')), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))); if ($r) { foreach ($r as $rr) { if ($rr['adjust']) { $md = datetime_convert('UTC', date_default_timezone_get(), $rr['start'], 'Y/m'); } else { $md = datetime_convert('UTC', 'UTC', $rr['start'], 'Y/m'); } $strt = datetime_convert('UTC', $rr['adjust'] ? date_default_timezone_get() : 'UTC', $rr['start']); $today = substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d') ? true : false; $when = day_translate(datetime_convert('UTC', $rr['adjust'] ? date_default_timezone_get() : 'UTC', $rr['start'], $bd_format)) . ($today ? ' ' . t('[today]') : ''); $result[] = array('notify_link' => $a->get_baseurl() . '/events', 'name' => $rr['xchan_name'], 'url' => $rr['xchan_url'], 'photo' => $rr['xchan_photo_s'], 'when' => $when, 'class' => 'notify-unseen', 'message' => t('posted an event')); } } logger('ping (all_events): ' . print_r($result, true), LOGGER_DATA); echo json_encode(array('notify' => $result)); killme(); } /** * Normal ping - just the counts, no detail */ $t = q("select count(*) as total from notify where uid = %d and seen = 0", intval(local_user())); if ($t) { $result['notify'] = intval($t[0]['total']); } $t1 = dba_timer(); $r = q("SELECT id, item_restrict, item_flags FROM item\n\t\tWHERE (item_restrict = %d) and ( item_flags & %d ) and uid = %d", intval(ITEM_VISIBLE), intval(ITEM_UNSEEN), intval(local_user())); if (count($r)) { $arr = array('items' => $r); call_hooks('network_ping', $arr); foreach ($r as $it) { if ($it['item_flags'] & ITEM_WALL) { $result['home']++; } else { $result['network']++; } } } $t2 = dba_timer(); $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and (abook_flags & %d) and not ((abook_flags & %d) or (xchan_flags & %d))", intval(local_user()), intval(ABOOK_FLAG_PENDING), intval(ABOOK_FLAG_SELF | ABOOK_FLAG_IGNORED), intval(XCHAN_FLAGS_DELETED | XCHAN_FLAGS_ORPHAN)); $t3 = dba_timer(); if ($intr) { $result['intros'] = intval($intr[0]['total']); } $t4 = dba_timer(); $channel = get_app()->get_channel(); $mails = q("SELECT count(id) as total from mail\n\t\tWHERE channel_id = %d AND not (mail_flags & %d) and from_xchan != '%s' ", intval(local_user()), intval(MAIL_SEEN), dbesc($channel['channel_hash'])); if ($mails) { $result['mail'] = intval($mails[0]['total']); } if ($a->config['system']['register_policy'] == REGISTER_APPROVE && is_site_admin()) { $regs = q("SELECT count(account_id) as total from account where (account_flags & %d)", intval(ACCOUNT_PENDING)); if ($regs) { $result['register'] = intval($regs[0]['total']); } } $t5 = dba_timer(); $events = q("SELECT type, start, adjust FROM `event`\n\t\tWHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0\n\t\tORDER BY `start` ASC ", intval(local_user()), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + 7 days')), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))); if ($events) { $result['all_events'] = count($events); if ($result['all_events']) { $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d'); foreach ($events as $x) { $bd = false; if ($x['type'] === 'birthday') { $result['birthdays']++; $bd = true; } else { $result['events']++; } if (datetime_convert('UTC', intval($x['adjust']) ? date_default_timezone_get() : 'UTC', $x['start'], 'Y-m-d') === $str_now) { $result['all_events_today']++; if ($bd) { $result['birthdays_today']++; } else { $result['events_today']++; } } } } } $x = json_encode($result); $t6 = dba_timer(); // logger('ping timer: ' . sprintf('%01.4f %01.4f %01.4f %01.4f %01.4f %01.4f',$t6 - $t5, $t5 - $t4, $t4 - $t3, $t3 - $t2, $t2 - $t1, $t1 - $t0)); echo $x; killme(); }
function init() { $result = array(); $notifs = array(); $result['notify'] = 0; $result['home'] = 0; $result['network'] = 0; $result['intros'] = 0; $result['mail'] = 0; $result['register'] = 0; $result['events'] = 0; $result['events_today'] = 0; $result['birthdays'] = 0; $result['birthdays_today'] = 0; $result['all_events'] = 0; $result['all_events_today'] = 0; $result['notice'] = array(); $result['info'] = array(); $t0 = dba_timer(); header("content-type: application/json"); $vnotify = false; $item_normal = item_normal(); if (local_channel()) { $vnotify = get_pconfig(local_channel(), 'system', 'vnotify'); $evdays = intval(get_pconfig(local_channel(), 'system', 'evdays')); $ob_hash = get_observer_hash(); } // if unset show all visual notification types if ($vnotify === false) { $vnotify = -1; } if ($evdays < 1) { $evdays = 3; } /** * If you have several windows open to this site and switch to a different channel * in one of them, the others may get into a confused state showing you a page or options * on that page which were only valid under the old identity. You session has changed. * Therefore we send a notification of this fact back to the browser where it is picked up * in javascript and which reloads the page it is on so that it is valid under the context * of the now current channel. */ $result['invalid'] = intval($_GET['uid']) && intval($_GET['uid']) != local_channel() ? 1 : 0; /** * Send all system messages (alerts) to the browser. * Some are marked as informational and some represent * errors or serious notifications. These typically * will popup on the current page (no matter what page it is) */ if (x($_SESSION, 'sysmsg')) { foreach ($_SESSION['sysmsg'] as $m) { $result['notice'][] = array('message' => $m); } unset($_SESSION['sysmsg']); } if (x($_SESSION, 'sysmsg_info')) { foreach ($_SESSION['sysmsg_info'] as $m) { $result['info'][] = array('message' => $m); } unset($_SESSION['sysmsg_info']); } if (!($vnotify & VNOTIFY_INFO)) { $result['info'] = array(); } if (!($vnotify & VNOTIFY_ALERT)) { $result['notice'] = array(); } if (\App::$install) { echo json_encode($result); killme(); } /** * Update chat presence indication (if applicable) */ if (get_observer_hash() && !$result['invalid']) { $r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1", dbesc(get_observer_hash()), dbesc($_SERVER['REMOTE_ADDR'])); $basic_presence = false; if ($r) { $basic_presence = true; q("update chatpresence set cp_last = '%s' where cp_id = %d", dbesc(datetime_convert()), intval($r[0]['cp_id'])); } if (!$basic_presence) { q("insert into chatpresence ( cp_xchan, cp_last, cp_status, cp_client)\n\t\t\t\t\tvalues( '%s', '%s', '%s', '%s' ) ", dbesc(get_observer_hash()), dbesc(datetime_convert()), dbesc('online'), dbesc($_SERVER['REMOTE_ADDR'])); } } /** * Chatpresence continued... if somebody hasn't pinged recently, they've most likely left the page * and shouldn't count as online anymore. We allow an expection for bots. */ q("delete from chatpresence where cp_last < %s - INTERVAL %s and cp_client != 'auto' ", db_utcnow(), db_quoteinterval('3 MINUTE')); if (!local_channel() || $result['invalid']) { echo json_encode($result); killme(); } /** * Everything following is only permitted under the context of a locally authenticated site member. */ /** * Handle "mark all xyz notifications read" requests. */ // mark all items read if (x($_REQUEST, 'markRead') && local_channel()) { switch ($_REQUEST['markRead']) { case 'network': $r = q("update item set item_unseen = 0 where item_unseen = 1 and uid = %d", intval(local_channel())); break; case 'home': $r = q("update item set item_unseen = 0 where item_unseen = 1 and item_wall = 1 and uid = %d", intval(local_channel())); break; case 'messages': $r = q("update mail set mail_seen = 1 where mail_seen = 0 and channel_id = %d ", intval(local_channel())); break; case 'all_events': $r = q("update event set `dismissed` = 1 where `dismissed` = 0 and uid = %d AND dtstart < '%s' AND dtstart > '%s' ", intval(local_channel()), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))); break; case 'notify': $r = q("update notify set seen = 1 where uid = %d", intval(local_channel())); break; default: break; } } if (x($_REQUEST, 'markItemRead') && local_channel()) { $r = q("update item set item_unseen = 0 where parent = %d and uid = %d", intval($_REQUEST['markItemRead']), intval(local_channel())); } /** * URL ping/something will return detail for "something", e.g. a json list with which to populate a notification * dropdown menu. */ if (argc() > 1 && argv(1) === 'notify') { $t = q("select count(*) as total from notify where uid = %d and seen = 0", intval(local_channel())); if ($t && intval($t[0]['total']) > 49) { $z = q("select * from notify where uid = %d\n\t\t\t\t\tand seen = 0 order by created desc limit 50", intval(local_channel())); } else { $z1 = q("select * from notify where uid = %d\n\t\t\t\t\tand seen = 0 order by created desc limit 50", intval(local_channel())); $z2 = q("select * from notify where uid = %d\n\t\t\t\t\tand seen = 1 order by created desc limit %d", intval(local_channel()), intval(50 - intval($t[0]['total']))); $z = array_merge($z1, $z2); } if (count($z)) { foreach ($z as $zz) { $notifs[] = array('notify_link' => z_root() . '/notify/view/' . $zz['id'], 'name' => $zz['xname'], 'url' => $zz['url'], 'photo' => $zz['photo'], 'when' => relative_date($zz['created']), 'hclass' => $zz['seen'] ? 'notify-seen' : 'notify-unseen', 'message' => strip_tags(bbcode($zz['msg']))); } } echo json_encode(array('notify' => $notifs)); killme(); } if (argc() > 1 && argv(1) === 'messages') { $channel = \App::get_channel(); $t = q("select mail.*, xchan.* from mail left join xchan on xchan_hash = from_xchan \n\t\t\t\twhere channel_id = %d and mail_seen = 0 and mail_deleted = 0 \n\t\t\t\tand from_xchan != '%s' order by created desc limit 50", intval(local_channel()), dbesc($channel['channel_hash'])); if ($t) { foreach ($t as $zz) { $notifs[] = array('notify_link' => z_root() . '/mail/' . $zz['id'], 'name' => $zz['xchan_name'], 'url' => $zz['xchan_url'], 'photo' => $zz['xchan_photo_s'], 'when' => relative_date($zz['created']), 'hclass' => intval($zz['mail_seen']) ? 'notify-seen' : 'notify-unseen', 'message' => t('sent you a private message')); } } echo json_encode(array('notify' => $notifs)); killme(); } if (argc() > 1 && (argv(1) === 'network' || argv(1) === 'home')) { $result = array(); $r = q("SELECT * FROM item\n\t\t\t\tWHERE item_unseen = 1 and uid = %d {$item_normal}\n\t\t\t\tand author_xchan != '%s' ORDER BY created DESC limit 300", intval(local_channel()), dbesc($ob_hash)); if ($r) { xchan_query($r); foreach ($r as $item) { if (argv(1) === 'home' && !intval($item['item_wall'])) { continue; } $result[] = \Zotlabs\Lib\Enotify::format($item); } } // logger('ping (network||home): ' . print_r($result, true), LOGGER_DATA); echo json_encode(array('notify' => $result)); killme(); } if (argc() > 1 && argv(1) === 'intros') { $result = array(); $r = q("SELECT * FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ORDER BY abook_created DESC LIMIT 50", intval(local_channel())); if ($r) { foreach ($r as $rr) { $result[] = array('notify_link' => z_root() . '/connections/ifpending', 'name' => $rr['xchan_name'], 'url' => $rr['xchan_url'], 'photo' => $rr['xchan_photo_s'], 'when' => relative_date($rr['abook_created']), 'hclass' => 'notify-unseen', 'message' => t('added your channel')); } } logger('ping (intros): ' . print_r($result, true), LOGGER_DATA); echo json_encode(array('notify' => $result)); killme(); } if (argc() > 1 && argv(1) === 'all_events') { $bd_format = t('g A l F d'); // 8 AM Friday January 18 $result = array(); $r = q("SELECT * FROM event left join xchan on event_xchan = xchan_hash\n\t\t\t\tWHERE `event`.`uid` = %d AND dtstart < '%s' AND dtstart > '%s' and `dismissed` = 0\n\t\t\t\tand etype in ( 'event', 'birthday' )\n\t\t\t\tORDER BY `dtstart` DESC LIMIT 1000", intval(local_channel()), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))); if ($r) { foreach ($r as $rr) { if ($rr['adjust']) { $md = datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'Y/m'); } else { $md = datetime_convert('UTC', 'UTC', $rr['dtstart'], 'Y/m'); } $strt = datetime_convert('UTC', $rr['adjust'] ? date_default_timezone_get() : 'UTC', $rr['dtstart']); $today = substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d') ? true : false; $when = day_translate(datetime_convert('UTC', $rr['adjust'] ? date_default_timezone_get() : 'UTC', $rr['dtstart'], $bd_format)) . ($today ? ' ' . t('[today]') : ''); $result[] = array('notify_link' => z_root() . '/events', 'name' => $rr['xchan_name'], 'url' => $rr['xchan_url'], 'photo' => $rr['xchan_photo_s'], 'when' => $when, 'hclass' => 'notify-unseen', 'message' => t('posted an event')); } } logger('ping (all_events): ' . print_r($result, true), LOGGER_DATA); echo json_encode(array('notify' => $result)); killme(); } /** * Normal ping - just the counts, no detail */ if ($vnotify & VNOTIFY_SYSTEM) { $t = q("select count(*) as total from notify where uid = %d and seen = 0", intval(local_channel())); if ($t) { $result['notify'] = intval($t[0]['total']); } } $t1 = dba_timer(); if ($vnotify & (VNOTIFY_NETWORK | VNOTIFY_CHANNEL)) { $r = q("SELECT id, item_wall FROM item\n\t\t\t\tWHERE item_unseen = 1 and uid = %d\n\t\t\t\t{$item_normal}\n\t\t\t\tand author_xchan != '%s'", intval(local_channel()), dbesc($ob_hash)); if ($r) { $arr = array('items' => $r); call_hooks('network_ping', $arr); foreach ($r as $it) { if (intval($it['item_wall'])) { $result['home']++; } else { $result['network']++; } } } } if (!($vnotify & VNOTIFY_NETWORK)) { $result['network'] = 0; } if (!($vnotify & VNOTIFY_CHANNEL)) { $result['home'] = 0; } $t2 = dba_timer(); if ($vnotify & VNOTIFY_INTRO) { $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ", intval(local_channel())); $t3 = dba_timer(); if ($intr) { $result['intros'] = intval($intr[0]['total']); } } $t4 = dba_timer(); $channel = \App::get_channel(); if ($vnotify & VNOTIFY_MAIL) { $mails = q("SELECT count(id) as total from mail\n\t\t\t\tWHERE channel_id = %d AND mail_seen = 0 and from_xchan != '%s' ", intval(local_channel()), dbesc($channel['channel_hash'])); if ($mails) { $result['mail'] = intval($mails[0]['total']); } } if ($vnotify & VNOTIFY_REGISTER) { if (\App::$config['system']['register_policy'] == REGISTER_APPROVE && is_site_admin()) { $regs = q("SELECT count(account_id) as total from account where (account_flags & %d) > 0", intval(ACCOUNT_PENDING)); if ($regs) { $result['register'] = intval($regs[0]['total']); } } } $t5 = dba_timer(); if ($vnotify & (VNOTIFY_EVENT | VNOTIFY_EVENTTODAY | VNOTIFY_BIRTHDAY)) { $events = q("SELECT etype, dtstart, adjust FROM `event`\n\t\t\t\tWHERE `event`.`uid` = %d AND dtstart < '%s' AND dtstart > '%s' and `dismissed` = 0\n\t\t\t\tand etype in ( 'event', 'birthday' )\n\t\t\t\tORDER BY `dtstart` ASC ", intval(local_channel()), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))); if ($events) { $result['all_events'] = count($events); if ($result['all_events']) { $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d'); foreach ($events as $x) { $bd = false; if ($x['etype'] === 'birthday') { $result['birthdays']++; $bd = true; } else { $result['events']++; } if (datetime_convert('UTC', intval($x['adjust']) ? date_default_timezone_get() : 'UTC', $x['dtstart'], 'Y-m-d') === $str_now) { $result['all_events_today']++; if ($bd) { $result['birthdays_today']++; } else { $result['events_today']++; } } } } } } if (!($vnotify & VNOTIFY_EVENT)) { $result['all_events'] = $result['events'] = 0; } if (!($vnotify & VNOTIFY_EVENTTODAY)) { $result['all_events_today'] = $result['events_today'] = 0; } if (!($vnotify & VNOTIFY_BIRTHDAY)) { $result['birthdays'] = 0; } $x = json_encode($result); $t6 = dba_timer(); // logger('ping timer: ' . sprintf('%01.4f %01.4f %01.4f %01.4f %01.4f %01.4f',$t6 - $t5, $t5 - $t4, $t4 - $t3, $t3 - $t2, $t2 - $t1, $t1 - $t0)); echo $x; killme(); }
function items_fetch($arr, $channel = null, $observer_hash = null, $client_mode = CLIENT_MODE_NORMAL, $module = 'network') { $result = array('success' => false); $a = get_app(); $sql_extra = ''; $sql_nets = ''; $sql_options = ''; $sql_extra2 = ''; $sql_extra3 = ''; $def_acl = ''; $item_uids = ' true '; if ($arr['uid']) { $uid = $arr['uid']; } if ($channel) { $uid = $channel['channel_id']; $uidhash = $channel['channel_hash']; $item_uids = " item.uid = " . intval($uid) . " "; } if ($arr['star']) { $sql_options .= " and (item_flags & " . intval(ITEM_STARRED) . ") "; } if ($arr['wall']) { $sql_options .= " and (item_flags & " . intval(ITEM_WALL) . ") "; } $sql_extra = " AND item.parent IN ( SELECT parent FROM item WHERE (item_flags & " . intval(ITEM_THREAD_TOP) . ") {$sql_options} ) "; if ($arr['since_id']) { $sql_extra .= " and item.id > " . $since_id . " "; } if ($arr['gid'] && $uid) { $r = q("SELECT * FROM `groups` WHERE id = %d AND uid = %d LIMIT 1", intval($arr['group']), intval($uid)); if (!$r) { $result['message'] = t('Collection not found.'); return $result; } $contact_str = ''; $contacts = group_get_members($group); if ($contacts) { foreach ($contacts as $c) { if ($contact_str) { $contact_str .= ','; } $contact_str .= "'" . $c['xchan'] . "'"; } } else { $contact_str = ' 0 '; $result['message'] = t('Collection is empty.'); return $result; } $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true {$sql_options} AND (( author_xchan IN ( {$contact_str} ) OR owner_xchan in ( {$contact_str})) or allow_gid like '" . protect_sprintf('%<' . dbesc($r[0]['hash']) . '>%') . "' ) and id = parent and item_restrict = 0 ) "; $x = group_rec_byhash($uid, $r[0]['hash']); $result['headline'] = sprintf(t('Collection: %s'), $x['name']); } elseif ($arr['cid'] && $uid) { $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and not ( abook_flags & " . intval(ABOOK_FLAG_BLOCKED) . ") limit 1", intval($arr['cid']), intval(local_user())); if ($r) { $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true {$sql_options} AND uid = " . intval($arr['uid']) . " AND ( author_xchan = '" . dbesc($r[0]['abook_xchan']) . "' or owner_xchan = '" . dbesc($r[0]['abook_xchan']) . "' ) and item_restrict = 0 ) "; $result['headline'] = sprintf(t('Connection: %s'), $r[0]['xchan_name']); } else { $result['message'] = t('Connection not found.'); return $result; } } if ($arr['datequery']) { $sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $arr['datequery'])))); } if ($arr['datequery2']) { $sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $arr['datequery2'])))); } if (!array_key_exists('nouveau', $arr)) { $sql_extra2 = " AND item.parent = item.id "; $sql_extra3 = ''; } if ($arr['search']) { if (strpos($arr['search'], '#') === 0) { $sql_extra .= term_query('item', substr($arr['search'], 1), TERM_HASHTAG); } else { $sql_extra .= sprintf(" AND item.body like '%s' ", dbesc(protect_sprintf('%' . $arr['search'] . '%'))); } } if (strlen($arr['file'])) { $sql_extra .= term_query('item', $arr['files'], TERM_FILE); } if ($arr['conv'] && $channel) { $sql_extra .= sprintf(" AND parent IN (SELECT distinct parent from item where ( author_xchan like '%s' or ( item_flags & %d ))) ", dbesc(protect_sprintf($uidhash)), intval(ITEM_MENTIONSME)); } if ($client_mode & CLIENT_MODE_UPDATE && !($client_mode & CLIENT_MODE_LOAD)) { // only setup pagination on initial page view $pager_sql = ''; } else { $itemspage = $channel ? get_pconfig($uid, 'system', 'itemspage') : 20; $a->set_pager_itemspage(intval($itemspage) ? $itemspage : 20); $pager_sql = sprintf(" LIMIT %d, %d ", intval(get_app()->pager['start']), intval(get_app()->pager['itemspage'])); } if (isset($arr['start']) && isset($arr['records'])) { $pager_sql = sprintf(" LIMIT %d, %d ", intval($arr['start']), intval($arr['records'])); } if (array_key_exists('cmin', $arr) || array_key_exists('cmax', $arr)) { if ($arr['cmin'] != 0 || $arr['cmax'] != 99) { // Not everybody who shows up in the network stream will be in your address book. // By default those that aren't are assumed to have closeness = 99; but this isn't // recorded anywhere. So if cmax is 99, we'll open the search up to anybody in // the stream with a NULL address book entry. $sql_nets .= " AND "; if ($arr['cmax'] == 99) { $sql_nets .= " ( "; } $sql_nets .= "( abook.abook_closeness >= " . intval($arr['cmin']) . " "; $sql_nets .= " AND abook.abook_closeness <= " . intval($arr['cmax']) . " ) "; if ($cmax == 99) { $sql_nets .= " OR abook.abook_closeness IS NULL ) "; } } } $simple_update = $client_mode & CLIENT_MODE_UPDATE ? " and ( item.item_flags & " . intval(ITEM_UNSEEN) . " ) " : ''; if ($client_mode & CLIENT_MODE_LOAD) { $simple_update = ''; } $start = dba_timer(); require_once 'include/security.php'; $sql_extra .= item_permissions_sql($channel['channel_id']); if ($arr['pages']) { $item_restrict = " AND (item_restrict & " . ITEM_WEBPAGE . ") "; } else { $item_restrict = " AND item_restrict = 0 "; } if ($arr['nouveau'] && $client_mode & CLIENT_MODE_LOAD && $channel) { // "New Item View" - show all items unthreaded in reverse created date order $items = q("SELECT item.*, item.id AS item_id FROM item\n WHERE {$item_uids} {$item_restrict}\n {$simple_update}\n {$sql_extra} {$sql_nets}\n ORDER BY item.received DESC {$pager_sql} "); require_once 'include/items.php'; xchan_query($items); $items = fetch_post_tags($items, true); } else { // Normal conversation view if ($arr['order'] === 'post') { $ordering = "created"; } else { $ordering = "commented"; } if ($client_mode & CLIENT_MODE_LOAD || $client_mode == CLIENT_MODE_NORMAL) { // Fetch a page full of parent items for this page $r = q("SELECT distinct item.id AS item_id FROM item\n left join abook on item.author_xchan = abook.abook_xchan\n WHERE {$item_uids} {$item_restrict}\n AND item.parent = item.id\n and ((abook.abook_flags & %d) = 0 or abook.abook_flags is null)\n {$sql_extra3} {$sql_extra} {$sql_nets}\n ORDER BY item.{$ordering} DESC {$pager_sql} ", intval(ABOOK_FLAG_BLOCKED)); } else { // update $r = q("SELECT item.parent AS item_id FROM item\n left join abook on item.author_xchan = abook.abook_xchan\n WHERE {$item_uids} {$item_restrict} {$simple_update}\n and ((abook.abook_flags & %d) = 0 or abook.abook_flags is null)\n {$sql_extra3} {$sql_extra} {$sql_nets} ", intval(ABOOK_FLAG_BLOCKED)); } $first = dba_timer(); // Then fetch all the children of the parents that are on this page if ($r) { $parents_str = ids_to_querystr($r, 'item_id'); if ($arr['top']) { $sql_extra = ' and id = parent ' . $sql_extra; } $items = q("SELECT item.*, item.id AS item_id FROM item\n WHERE {$item_uids} {$item_restrict}\n AND item.parent IN ( %s )\n {$sql_extra} ", dbesc($parents_str)); $second = dba_timer(); xchan_query($items); $third = dba_timer(); $items = fetch_post_tags($items, true); $fourth = dba_timer(); require_once 'include/conversation.php'; $items = conv_sort($items, $ordering); //logger('items: ' . print_r($items,true)); } else { $items = array(); } if ($parents_str && $arr['mark_seen']) { $update_unseen = ' AND parent IN ( ' . dbesc($parents_str) . ' )'; } // FIXME finish mark unseen sql } return $items; }
function content_content(&$a, $update = 0) { require_once 'include/conversation.php'; // Currently security is based on the logged in user if (!local_user()) { return; } $arr = array('query' => $a->query_string); call_hooks('content_content_init', $arr); $datequery = $datequery2 = ''; $group = 0; $nouveau = false; if ($a->argc > 1) { for ($x = 1; $x < $a->argc; $x++) { if (is_a_date_arg($a->argv[$x])) { if ($datequery) { $datequery2 = escape_tags($a->argv[$x]); } else { $datequery = escape_tags($a->argv[$x]); $_GET['order'] = 'post'; } } elseif ($a->argv[$x] === 'new') { $nouveau = true; } elseif (intval($a->argv[$x])) { $group = intval($a->argv[$x]); $def_acl = array('allow_gid' => '<' . $group . '>'); } } } $o = ''; $contact_id = $a->cid; require_once 'include/acl_selectors.php'; $cid = x($_GET, 'cid') ? intval($_GET['cid']) : 0; $star = x($_GET, 'star') ? intval($_GET['star']) : 0; $bmark = x($_GET, 'bmark') ? intval($_GET['bmark']) : 0; $order = x($_GET, 'order') ? notags($_GET['order']) : 'comment'; $liked = x($_GET, 'liked') ? intval($_GET['liked']) : 0; $conv = x($_GET, 'conv') ? intval($_GET['conv']) : 0; $spam = x($_GET, 'spam') ? intval($_GET['spam']) : 0; $nets = x($_GET, 'nets') ? $_GET['nets'] : ''; $cmin = x($_GET, 'cmin') ? intval($_GET['cmin']) : 0; $cmax = x($_GET, 'cmax') ? intval($_GET['cmax']) : 99; $file = x($_GET, 'file') ? $_GET['file'] : ''; if (x($_GET, 'search') || x($_GET, 'file')) { $nouveau = true; } if ($cid) { $def_acl = array('allow_cid' => '<' . intval($cid) . '>'); } if ($nets) { $r = q("select id from contact where uid = %d and network = '%s' and self = 0", intval(local_user()), dbesc($nets)); $str = ''; if (count($r)) { foreach ($r as $rr) { $str .= '<' . $rr['id'] . '>'; } } if (strlen($str)) { $def_acl = array('allow_cid' => $str); } } $sql_options = $star ? " and starred = 1 " : ''; $sql_options .= $bmark ? " and bookmark = 1 " : ''; $sql_nets = $nets ? sprintf(" and `contact`.`network` = '%s' ", dbesc($nets)) : ''; $sql_extra = " AND `item`.`parent` IN ( SELECT `parent` FROM `item` WHERE `id` = `parent` {$sql_options} ) "; if ($group) { $r = q("SELECT `name`, `id` FROM `group` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($group), intval($_SESSION['uid'])); if (!count($r)) { if ($update) { killme(); } notice(t('No such group') . EOL); goaway($a->get_baseurl(true) . '/network'); // NOTREACHED } $contacts = expand_groups(array($group)); if (is_array($contacts) && count($contacts)) { $contact_str = implode(',', $contacts); } else { $contact_str = ' 0 '; info(t('Group is empty')); } $sql_extra = " AND `item`.`parent` IN ( SELECT DISTINCT(`parent`) FROM `item` WHERE 1 {$sql_options} AND ( `contact-id` IN ( {$contact_str} ) OR `allow_gid` like '" . protect_sprintf('%<' . intval($group) . '>%') . "' ) and deleted = 0 ) "; $o = replace_macros(get_markup_template("section_title.tpl"), array('$title' => sprintf(t('Group: %s'), $r[0]['name']))) . $o; } elseif ($cid) { $r = q("SELECT `id`,`name`,`network`,`writable`,`nurl` FROM `contact` WHERE `id` = %d \n\t\t\t\tAND `blocked` = 0 AND `pending` = 0 LIMIT 1", intval($cid)); if (count($r)) { $sql_extra = " AND `item`.`parent` IN ( SELECT DISTINCT(`parent`) FROM `item` WHERE 1 {$sql_options} AND `contact-id` = " . intval($cid) . " and deleted = 0 ) "; } else { killme(); } } $sql_extra3 = ''; if ($datequery) { $sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery)))); } if ($datequery2) { $sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery2)))); } $sql_extra2 = $nouveau ? '' : " AND `item`.`parent` = `item`.`id` "; $sql_extra3 = $nouveau ? '' : $sql_extra3; $sql_table = "`item`"; if (x($_GET, 'search')) { $search = escape_tags($_GET['search']); if (strpos($search, '#') === 0) { $tag = true; $search = substr($search, 1); } if (get_config('system', 'only_tag_search')) { $tag = true; } if ($tag) { //$sql_extra = sprintf(" AND `term`.`term` = '%s' AND `term`.`otype` = %d AND `term`.`type` = %d ", // dbesc(protect_sprintf($search)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG)); //$sql_table = "`term` INNER JOIN `item` ON `item`.`id` = `term`.`oid` AND `item`.`uid` = `term`.`uid` "; $sql_extra = ""; $sql_table = sprintf("`item` INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", dbesc(protect_sprintf($search)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval(local_user())); } else { if (get_config('system', 'use_fulltext_engine')) { $sql_extra = sprintf(" AND MATCH (`item`.`body`, `item`.`title`) AGAINST ('%s' in boolean mode) ", dbesc(protect_sprintf($search))); } else { $sql_extra = sprintf(" AND `item`.`body` REGEXP '%s' ", dbesc(protect_sprintf(preg_quote($search)))); } } } if (strlen($file)) { $sql_extra .= file_tag_file_query('item', unxmlify($file)); } if ($conv) { $myurl = $a->get_baseurl() . '/profile/' . $a->user['nickname']; $myurl = substr($myurl, strpos($myurl, '://') + 3); $myurl = str_replace('www.', '', $myurl); $diasp_url = str_replace('/profile/', '/u/', $myurl); $sql_extra .= sprintf(" AND `item`.`parent` IN (SELECT distinct(`parent`) from item where `author-link` IN ('https://%s', 'http://%s') OR `mention`)", dbesc(protect_sprintf($myurl)), dbesc(protect_sprintf($myurl))); } $pager_sql = sprintf(" LIMIT %d, %d ", intval($a->pager['start']), intval($a->pager['itemspage'])); if ($nouveau) { // "New Item View" - show all items unthreaded in reverse created date order $items = q("SELECT `item`.*, `item`.`id` AS `item_id`,\n\t\t\t`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, `contact`.`writable`,\n\t\t\t`contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,\n\t\t\t`contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`\n\t\t\tFROM {$sql_table} INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`\n\t\t\tWHERE `item`.`uid` = %d AND `item`.`visible` = 1\n\t\t\tAND `item`.`deleted` = 0 and `item`.`moderated` = 0\n\t\t\t{$simple_update}\n\t\t\tAND `contact`.`blocked` = 0 AND `contact`.`pending` = 0\n\t\t\t{$sql_extra} {$sql_nets}\n\t\t\tORDER BY `item`.`received` DESC {$pager_sql} ", intval($_SESSION['uid'])); } else { // Normal conversation view if ($order === 'post') { $ordering = "`created`"; } else { $ordering = "`commented`"; } $start = dba_timer(); $r = q("SELECT `item`.`id` AS `item_id`, `contact`.`uid` AS `contact_uid`\n\t\t\tFROM {$sql_table} INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`\n\t\t\tWHERE `item`.`uid` = %d AND `item`.`visible` = 1 AND `item`.`deleted` = 0\n\t\t\tAND `item`.`moderated` = 0 AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0\n\t\t\tAND `item`.`parent` = `item`.`id`\n\t\t\t{$sql_extra3} {$sql_extra} {$sql_nets}\n\t\t\tORDER BY `item`.{$ordering} DESC {$pager_sql} ", intval(local_user())); $first = dba_timer(); // Then fetch all the children of the parents that are on this page $parents_arr = array(); $parents_str = ''; if (count($r)) { foreach ($r as $rr) { if (!in_array($rr['item_id'], $parents_arr)) { $parents_arr[] = $rr['item_id']; } } $parents_str = implode(', ', $parents_arr); $items = q("SELECT `item`.*, `item`.`id` AS `item_id`,\n\t\t\t\t`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`alias`, `contact`.`rel`, `contact`.`writable`,\n\t\t\t\t`contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,\n\t\t\t\t`contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`\n\t\t\t\tFROM {$sql_table} INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`\n\t\t\t\tWHERE `item`.`uid` = %d AND `item`.`visible` = 1 AND `item`.`deleted` = 0\n\t\t\t\tAND `item`.`moderated` = 0\n\t\t\t\tAND `contact`.`blocked` = 0 AND `contact`.`pending` = 0\n\t\t\t\tAND `item`.`parent` IN ( %s )\n\t\t\t\t{$sql_extra} ", intval(local_user()), dbesc($parents_str)); $second = dba_timer(); $items = conv_sort($items, $ordering); } else { $items = array(); } } logger('parent dba_timer: ' . sprintf('%01.4f', $first - $start)); logger('child dba_timer: ' . sprintf('%01.4f', $second - $first)); // Set this so that the conversation function can find out contact info for our wall-wall items $a->page_contact = $a->contact; $mode = $nouveau ? 'network-new' : 'network'; $o = render_content($a, $items, $mode, false); header('Content-type: application/json'); echo json_encode($o); killme(); }
public function replace_macros($s, $r) { $this->r = $r; $s = $this->_build_nodes($s); $s = preg_replace_callback('/\\|\\|([0-9]+)\\|\\|/', array($this, "_replcb_node"), $s); if ($s == Null) { $this->_preg_error(); } // remove comments block $s = preg_replace('/{#[^#]*#}/', "", $s); $t2 = dba_timer(); // replace strings recursively (limit to 10 loops) $os = ""; $count = 0; while ($os !== $s && $count < 10) { $os = $s; $count++; $s = $this->var_replace($s); } return $s; }
/** * "Render" a conversation or list of items for HTML display. * There are two major forms of display: * - Sequential or unthreaded ("New Item View" or search results) * - conversation view * The $mode parameter decides between the various renderings and also * figures out how to determine page owner and other contextual items * that are based on unique features of the calling module. * */ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $prepared_item = '') { $tstart = dba_timer(); $t0 = $t1 = $t2 = $t3 = $t4 = $t5 = $t6 = null; $content_html = ''; $o = ''; require_once 'bbcode.php'; $ssl_state = local_user() ? true : false; if (local_user()) { load_pconfig(local_user(), ''); } $arr_blocked = null; if (local_user()) { $str_blocked = get_pconfig(local_user(), 'system', 'blocked'); if ($str_blocked) { $arr_blocked = explode(',', $str_blocked); for ($x = 0; $x < count($arr_blocked); $x++) { $arr_blocked[$x] = trim($arr_blocked[$x]); } } } $profile_owner = 0; $page_writeable = false; $live_update_div = ''; $preview = $page_mode === 'preview' ? true : false; $previewing = $preview ? ' preview ' : ''; if ($mode === 'network') { $t1 = dba_timer(); $profile_owner = local_user(); $page_writeable = true; if (!$update) { // The special div is needed for liveUpdate to kick in for this page. // We only launch liveUpdate if you aren't filtering in some incompatible // way and also you aren't writing a comment (discovered in javascript). $live_update_div = '<div id="live-network"></div>' . "\r\n" . "<script> var profile_uid = " . $_SESSION['uid'] . "; var netargs = '" . substr($a->cmd, 8) . '?f=' . (x($_GET, 'cid') ? '&cid=' . $_GET['cid'] : '') . (x($_GET, 'search') ? '&search=' . $_GET['search'] : '') . (x($_GET, 'star') ? '&star=' . $_GET['star'] : '') . (x($_GET, 'order') ? '&order=' . $_GET['order'] : '') . (x($_GET, 'bmark') ? '&bmark=' . $_GET['bmark'] : '') . (x($_GET, 'liked') ? '&liked=' . $_GET['liked'] : '') . (x($_GET, 'conv') ? '&conv=' . $_GET['conv'] : '') . (x($_GET, 'spam') ? '&spam=' . $_GET['spam'] : '') . (x($_GET, 'nets') ? '&nets=' . $_GET['nets'] : '') . (x($_GET, 'cmin') ? '&cmin=' . $_GET['cmin'] : '') . (x($_GET, 'cmax') ? '&cmax=' . $_GET['cmax'] : '') . (x($_GET, 'file') ? '&file=' . $_GET['file'] : '') . (x($_GET, 'uri') ? '&uri=' . $_GET['uri'] : '') . "'; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; } } elseif ($mode === 'channel') { $profile_owner = $a->profile['profile_uid']; $page_writeable = $profile_owner == local_user(); if (!$update) { $tab = notags(trim($_GET['tab'])); if ($tab === 'posts') { // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, // because browser prefetching might change it on us. We have to deliver it with the page. $live_update_div = '<div id="live-channel"></div>' . "\r\n" . "<script> var profile_uid = " . $a->profile['profile_uid'] . "; var netargs = '?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; } } } elseif ($mode === 'display') { $profile_owner = local_user(); $page_writeable = false; $live_update_div = '<div id="live-display"></div>' . "\r\n"; } elseif ($mode === 'page') { $profile_owner = $a->profile['uid']; $page_writeable = $profile_owner == local_user(); $live_update_div = '<div id="live-page"></div>' . "\r\n"; } elseif ($mode === 'search') { $live_update_div = '<div id="live-search"></div>' . "\r\n"; } elseif ($mode === 'photos') { $profile_onwer = $a->profile['profile_uid']; $page_writeable = $profile_owner == local_user(); $live_update_div = '<div id="live-photos"></div>' . "\r\n"; // for photos we've already formatted the top-level item (the photo) $content_html = $a->data['photo_html']; } $page_dropping = local_user() && local_user() == $profile_owner ? true : false; if (!feature_enabled($profile_owner, 'multi_delete')) { $page_dropping = false; } $channel = $a->get_channel(); $observer = $a->get_observer(); if ($update) { $return_url = $_SESSION['return_url']; } else { $return_url = $_SESSION['return_url'] = $a->query_string; } load_contact_links(local_user()); $cb = array('items' => $items, 'mode' => $mode, 'update' => $update, 'preview' => $preview); call_hooks('conversation_start', $cb); $items = $cb['items']; $alike = array(); $dlike = array(); // array with html for each thread (parent+comments) $threads = array(); $threadsid = -1; $page_template = get_markup_template("conversation.tpl"); if ($items) { if ($mode === 'network-new' || $mode === 'search' || $mode === 'community') { // "New Item View" on network page or search page results // - just loop through the items and format them minimally for display //$tpl = get_markup_template('search_item.tpl'); $tpl = 'search_item.tpl'; foreach ($items as $item) { if ($arr_blocked) { $blocked = false; foreach ($arr_blocked as $b) { if ($b && $item['author_xchan'] == $b) { $blocked = true; break; } } if ($blocked) { continue; } } $threadsid++; $comment = ''; $owner_url = ''; $owner_photo = ''; $owner_name = ''; $sparkle = ''; if ($mode === 'search' || $mode === 'community') { if ((activity_match($item['verb'], ACTIVITY_LIKE) || activity_match($item['verb'], ACTIVITY_DISLIKE)) && $item['id'] != $item['parent']) { continue; } $nickname = $item['nickname']; } else { $nickname = $a->user['nickname']; } $profile_name = strlen($item['author-name']) ? $item['author-name'] : $item['name']; if ($item['author-link'] && !$item['author-name']) { $profile_name = $item['author-link']; } $tags = array(); $hashtags = array(); $mentions = array(); $sp = false; $profile_link = best_link_url($item, $sp); if ($sp) { $sparkle = ' sparkle'; } else { $profile_link = zid($profile_link); } $normalised = normalise_link(strlen($item['author-link']) ? $item['author-link'] : $item['url']); if (x($a->contacts, $normalised)) { $profile_avatar = $a->contacts[$normalised]['thumb']; } else { $profile_avatar = strlen($item['author-avatar']) ? $a->get_cached_avatar_image($item['author-avatar']) : $item['thumb']; } $profile_name = $item['author']['xchan_name']; $profile_link = $item['author']['xchan_url']; $profile_avatar = $item['author']['xchan_photo_m']; $location = format_location($item); localize_item($item); if ($mode === 'network-new') { $dropping = true; } else { $dropping = false; } $drop = array('pagedropping' => $page_dropping, 'dropping' => $dropping, 'select' => t('Select'), 'delete' => t('Delete')); $star = false; $isstarred = "unstarred icon-star-empty"; $lock = $item['item_private'] || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid']) ? t('Private Message') : false; $likebuttons = false; $shareable = false; $verified = $item['item_flags'] & ITEM_VERIFIED ? t('Message is verified') : ''; $unverified = ''; $tags = array(); $terms = get_terms_oftype($item['term'], array(TERM_HASHTAG, TERM_MENTION, TERM_UNKNOWN)); if (count($terms)) { foreach ($terms as $tag) { $tags[] = format_term_for_display($tag); } } $body = prepare_body($item, true); //$tmp_item = replace_macros($tpl,array( $tmp_item = array('template' => $tpl, 'toplevel' => 'toplevel_item', 'mode' => $mode, 'id' => $preview ? 'P0' : $item['item_id'], 'linktitle' => sprintf(t('View %s\'s profile @ %s'), $profile_name, $profile_url), 'profile_url' => $profile_link, 'item_photo_menu' => item_photo_menu($item), 'name' => $profile_name, 'sparkle' => $sparkle, 'lock' => $lock, 'thumb' => $profile_avatar, 'title' => $item['title'], 'body' => $body, 'tags' => $tags, 'hashtags' => $hashtags, 'mentions' => $mentions, 'verified' => $verified, 'unverified' => $unverified, 'txt_cats' => t('Categories:'), 'txt_folders' => t('Filed under:'), 'has_cats' => count($categories) ? 'true' : '', 'has_folders' => count($folders) ? 'true' : '', 'categories' => $categories, 'folders' => $folders, 'text' => strip_tags($body), 'ago' => relative_date($item['created']), 'app' => $item['app'], 'str_app' => sprintf(t(' from %s'), $item['app']), 'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'), 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'), 'editedtime' => $item['edited'] != $item['created'] ? sprintf(t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : '', 'expiretime' => $item['expires'] !== NULL_DATE ? sprintf(t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')) : '', 'location' => $location, 'indent' => '', 'owner_name' => $owner_name, 'owner_url' => $owner_url, 'owner_photo' => $owner_photo, 'plink' => get_plink($item, false), 'edpost' => false, 'isstarred' => $isstarred, 'star' => $star, 'drop' => $drop, 'vote' => $likebuttons, 'like' => '', 'dislike' => '', 'comment' => '', 'conv' => $preview ? '' : array('href' => z_root() . '/display/' . $item['mid'], 'title' => t('View in context')), 'previewing' => $previewing, 'wait' => t('Please wait'), 'thread_level' => 1); $arr = array('item' => $item, 'output' => $tmp_item); call_hooks('display_item', $arr); // $threads[$threadsid]['id'] = $item['item_id']; $threads[] = $arr['output']; } } else { // Normal View // logger('conv: items: ' . print_r($items,true)); require_once 'include/ConversationObject.php'; require_once 'include/ItemObject.php'; $conv = new Conversation($mode, $preview, $prepared_item); // In the display mode we don't have a profile owner. if ($mode === 'display' && $items) { $conv->set_profile_owner($items[0]['uid']); } // get all the topmost parents // this shouldn't be needed, as we should have only them in our array // But for now, this array respects the old style, just in case $threads = array(); foreach ($items as $item) { // Check for any blocked authors if ($arr_blocked) { $blocked = false; foreach ($arr_blocked as $b) { if ($b && $item['author_xchan'] == $b) { $blocked = true; break; } } if ($blocked) { continue; } } // Check all the kids too if ($arr_blocked && $item['children']) { for ($d = 0; $d < count($item['children']); $d++) { foreach ($arr_blocked as $b) { if ($b && $item['children'][$d]['author_xchan'] == $b) { $item['children'][$d]['author_blocked'] = true; } } } } like_puller($a, $item, $alike, 'like'); if (feature_enabled($profile_owner, 'dislike')) { like_puller($a, $item, $dlike, 'dislike'); } if (!visible_activity($item)) { continue; } $item['pagedrop'] = $page_dropping; if ($item['id'] == $item['parent']) { // $tx1 = dba_timer(); $item_object = new Item($item); $conv->add_thread($item_object); if ($page_mode === 'list') { $item_object->set_template('conv_list.tpl'); } // $tx2 = dba_timer(); // if($mode === 'network') // profiler($tx1,$tx2,'add thread ' . $item['id']); } } $t2 = dba_timer(); $threads = $conv->get_template_data($alike, $dlike); if (!$threads) { logger('[ERROR] conversation : Failed to get template data.', LOGGER_DEBUG); $threads = array(); } $t3 = dba_timer(); if ($mode === 'network') { profiler($t1, $t2, 'Conversation prepare'); profiler($t2, $t3, 'Conversation get_template'); } } } if ($page_mode === 'traditional' || $page_mode === 'preview') { $page_template = get_markup_template("threaded_conversation.tpl"); } elseif ($update) { $page_template = get_markup_template("convobj.tpl"); } else { $page_template = get_markup_template("conv_frame.tpl"); $threads = null; } if ($page_mode === 'preview') { logger('preview: ' . print_r($threads, true)); } // Do not un-comment if smarty3 is in use // logger('page_template: ' . $page_template); // logger('nouveau: ' . print_r($threads,true)); $o .= replace_macros($page_template, array('$baseurl' => $a->get_baseurl($ssl_state), '$photo_item' => $content_html, '$live_update' => $live_update_div, '$remove' => t('remove'), '$mode' => $mode, '$user' => $a->user, '$threads' => $threads, '$wait' => t('Loading...'), '$dropping' => $page_dropping ? t('Delete Selected Items') : False)); if ($mode === 'network') { $t4 = dba_timer(); profiler($t3, $t4, 'conversation template'); } if ($page_mode === 'preview') { logger('preview: ' . $o); } return $o; }
function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) { $where = ''; $limit = ''; $t0 = dba_timer(); if ($numitems) { $limit = " LIMIT " . intval($numitems) . " OFFSET " . intval($start); } if ($mailbox !== '') { $x = q("select channel_hash from channel where channel_id = %d limit 1", intval($uid)); if (!$x) { return array(); } $channel_hash = dbesc($x[0]['channel_hash']); $local_channel = intval(local_channel()); switch ($mailbox) { case 'inbox': $sql = "SELECT * FROM mail WHERE channel_id = {$local_channel} AND from_xchan != '{$channel_hash}' ORDER BY created DESC {$limit}"; break; case 'outbox': $sql = "SELECT * FROM mail WHERE channel_id = {$local_channel} AND from_xchan = '{$channel_hash}' ORDER BY created DESC {$limit}"; break; case 'combined': $parents = q("SELECT parent_mid FROM mail WHERE mid = parent_mid AND channel_id = %d ORDER BY created DESC", dbesc($local_channel)); //FIXME: We need the latest mail of a thread here. This query throws errors in postgres. We now look for the latest in php until somebody can fix this... //$sql = "SELECT * FROM ( SELECT * FROM mail WHERE channel_id = $local_channel ORDER BY created DESC $limit ) AS temp_table GROUP BY parent_mid ORDER BY created DESC"; break; } } if ($parents) { foreach ($parents as $parent) { $all[] = q("SELECT * FROM mail WHERE parent_mid = '%s' AND channel_id = %d ORDER BY created DESC", dbesc($parent['parent_mid']), dbesc($local_channel)); } foreach ($all as $single) { $r[] = $single[0]; } } else { $r = q($sql); } if (!$r) { return array(); } $chans = array(); foreach ($r as $rr) { $s = "'" . dbesc(trim($rr['from_xchan'])) . "'"; if (!in_array($s, $chans)) { $chans[] = $s; } $s = "'" . dbesc(trim($rr['to_xchan'])) . "'"; if (!in_array($s, $chans)) { $chans[] = $s; } } $c = q("select * from xchan where xchan_hash in (" . implode(',', $chans) . ")"); foreach ($r as $k => $rr) { $r[$k]['from'] = find_xchan_in_array($rr['from_xchan'], $c); $r[$k]['to'] = find_xchan_in_array($rr['to_xchan'], $c); $r[$k]['seen'] = intval($rr['mail_seen']); if (intval($r[$k]['mail_obscured'])) { if ($r[$k]['title']) { $r[$k]['title'] = base64url_decode(str_rot47($r[$k]['title'])); } if ($r[$k]['body']) { $r[$k]['body'] = base64url_decode(str_rot47($r[$k]['body'])); } } } return $r; }
/** * Get data in a form usable by a conversation template * * Returns: * _ The data requested on success * _ false on failure */ public function get_template_data($alike, $dlike, $thread_level = 1) { $t1 = dba_timer(); $result = array(); $a = $this->get_app(); $item = $this->get_data(); $commentww = ''; $sparkle = ''; $buttons = ''; $dropping = false; $star = false; $isstarred = "unstarred icon-star-empty"; $indent = ''; $osparkle = ''; $total_children = $this->count_descendants(); $conv = $this->get_conversation(); $observer = $conv->get_observer(); $lock = $item['item_private'] == 1 || $item['uid'] == local_user() && (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) ? t('Private Message') : false; $shareable = $conv->get_profile_owner() == local_user() && $item['item_private'] != 1 ? true : false; // allow an exemption for sharing stuff from your private feeds if ($item['author']['xchan_network'] === 'rss') { $shareable = true; } $mode = $conv->get_mode(); if (local_user() && $observer['xchan_hash'] === $item['author_xchan']) { $edpost = array($a->get_baseurl($ssl_state) . "/editpost/" . $item['id'], t("Edit")); } else { $edpost = false; } if ($observer['xchan_hash'] == $this->get_data_value('author_xchan') || $observer['xchan_hash'] == $this->get_data_value('owner_xchan') || $this->get_data_value('uid') == local_user()) { $dropping = true; } if ($dropping) { $drop = array('dropping' => $dropping, 'delete' => t('Delete')); } // FIXME if ($observer_is_pageowner) { $multidrop = array('select' => t('Select')); } $filer = $conv->get_profile_owner() == local_user() ? t("Save to Folder") : false; $profile_avatar = $item['author']['xchan_photo_m']; $profile_link = chanlink_url($item['author']['xchan_url']); $profile_name = $item['author']['xchan_name']; $location = format_location($item); $like_count = x($alike, $item['mid']) ? $alike[$item['mid']] : ''; $like_list = x($alike, $item['mid']) ? $alike[$item['mid'] . '-l'] : ''; if (count($like_list) > MAX_LIKERS) { $like_list_part = array_slice($like_list, 0, MAX_LIKERS); array_push($like_list_part, '<a href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>'); } else { $like_list_part = ''; } $like_button_label = tt('Like', 'Likes', $like_count, 'noun'); if (feature_enabled($conv->get_profile_owner(), 'dislike')) { $dislike_count = x($dlike, $item['mid']) ? $dlike[$item['mid']] : ''; $dislike_list = x($dlike, $item['mid']) ? $dlike[$item['mid'] . '-l'] : ''; $dislike_button_label = tt('Dislike', 'Dislikes', $dislike_count, 'noun'); if (count($dislike_list) > MAX_LIKERS) { $dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS); array_push($dislike_list_part, '<a href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>'); } else { $dislike_list_part = ''; } } $showlike = x($alike, $item['mid']) ? format_like($alike[$item['mid']], $alike[$item['mid'] . '-l'], 'like', $item['mid']) : ''; $showdislike = x($dlike, $item['mid']) && feature_enabled($conv->get_profile_owner(), 'dislike') ? format_like($dlike[$item['mid']], $dlike[$item['mid'] . '-l'], 'dislike', $item['mid']) : ''; /* * We should avoid doing this all the time, but it depends on the conversation mode * And the conv mode may change when we change the conv, or it changes its mode * Maybe we should establish a way to be notified about conversation changes */ $this->check_wall_to_wall(); if ($this->is_toplevel()) { // FIXME check this permission if ($conv->get_profile_owner() == local_user()) { // FIXME we don't need all this stuff, some can be done in the template $star = array('do' => t("Add Star"), 'undo' => t("Remove Star"), 'toggle' => t("Toggle Star Status"), 'classdo' => $item['item_flags'] & ITEM_STARRED ? "hidden" : "", 'classundo' => $item['item_flags'] & ITEM_STARRED ? "" : "hidden", 'isstarred' => $item['item_flags'] & ITEM_STARRED ? "starred icon-star" : "unstarred icon-star-empty", 'starred' => t('starred')); } } else { $indent = 'comment'; } $verified = $item['item_flags'] & ITEM_VERIFIED ? t('Message is verified') : ''; $unverified = ''; // (($this->is_wall_to_wall() && (! ($item['item_flags'] & ITEM_VERIFIED))) ? t('Message cannot be verified') : ''); // FIXME - check this permission if ($conv->get_profile_owner() == local_user()) { $tagger = array('tagit' => t("Add Tag"), 'classtagger' => ""); } $has_bookmarks = false; if (is_array($item['term'])) { foreach ($item['term'] as $t) { if ($t['type'] == TERM_BOOKMARK) { $has_bookmarks = true; } } } $has_event = false; if ($item['obj_type'] === ACTIVITY_OBJ_EVENT && $conv->get_profile_owner() == local_user()) { $has_event = true; } if ($this->is_commentable()) { $like = array(t("I like this (toggle)"), t("like")); $dislike = array(t("I don't like this (toggle)"), t("dislike")); } if ($shareable) { $share = array(t('Share This'), t('share')); } if (strcmp(datetime_convert('UTC', 'UTC', $item['created']), datetime_convert('UTC', 'UTC', 'now - 12 hours')) > 0) { $indent .= ' shiny'; } $t2 = dba_timer(); localize_item($item); $t3 = dba_timer(); $body = prepare_body($item, true); $t4 = dba_timer(); $tmp_item = array('template' => $this->get_template(), 'mode' => $mode, 'type' => implode("", array_slice(explode("/", $item['verb']), -1)), 'tags' => array(), 'body' => $body, 'text' => strip_tags($body), 'id' => $this->get_id(), 'linktitle' => sprintf(t('View %s\'s profile - %s'), $profile_name, $item['author']['xchan_addr']), 'olinktitle' => sprintf(t('View %s\'s profile - %s'), $this->get_owner_name(), $item['owner']['xchan_addr']), 'to' => t('to'), 'via' => t('via'), 'wall' => t('Wall-to-Wall'), 'vwall' => t('via Wall-To-Wall:'), 'profile_url' => $profile_link, 'item_photo_menu' => item_photo_menu($item), 'name' => $profile_name, 'thumb' => $profile_avatar, 'osparkle' => $osparkle, 'sparkle' => $sparkle, 'title' => $item['title'], 'ago' => relative_date($item['created']), 'app' => $item['app'], 'str_app' => sprintf(t(' from %s'), $item['app']), 'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'), 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'), 'editedtime' => $item['edited'] != $item['created'] ? sprintf(t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : '', 'expiretime' => $item['expires'] !== NULL_DATE ? sprintf(t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')) : '', 'lock' => $lock, 'verified' => $verified, 'unverified' => $unverified, 'location' => $location, 'indent' => $indent, 'owner_url' => $this->get_owner_url(), 'owner_photo' => $this->get_owner_photo(), 'owner_name' => $this->get_owner_name(), 'like' => $like, 'dislike' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike : '', 'share' => $share, 'rawmid' => $item['mid'], 'plink' => get_plink($item), 'edpost' => feature_enabled($conv->get_profile_owner(), 'edit_posts') ? $edpost : '', 'star' => feature_enabled($conv->get_profile_owner(), 'star_posts') ? $star : '', 'tagger' => feature_enabled($conv->get_profile_owner(), 'commtag') ? $tagger : '', 'filer' => feature_enabled($conv->get_profile_owner(), 'filing') ? $filer : '', 'bookmark' => $conv->get_profile_owner() == local_user() && $has_bookmarks ? t('Save Bookmarks') : '', 'addtocal' => $has_event ? t('Add to Calendar') : '', 'drop' => $drop, 'multidrop' => feature_enabled($conv->get_profile_owner(), 'multi_delete') ? $multidrop : '', 'like_count' => $like_count, 'like_list' => $like_list, 'like_list_part' => $like_list_part, 'like_button_label' => $like_button_label, 'like_modal_title' => t('Likes', 'noun'), 'dislike_modal_title' => t('Dislikes', 'noun'), 'dislike_count' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_count : '', 'dislike_list' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_list : '', 'dislike_list_part' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_list_part : '', 'dislike_button_label' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_button_label : '', 'modal_dismiss' => t('Close'), 'showlike' => $showlike, 'showdislike' => $showdislike, 'comment' => $this->get_comment_box($indent), 'previewing' => $conv->is_preview() ? ' preview ' : '', 'wait' => t('Please wait'), 'thread_level' => $thread_level); $t5 = dba_timer(); $arr = array('item' => $item, 'output' => $tmp_item); call_hooks('display_item', $arr); $result = $arr['output']; $result['children'] = array(); $children = $this->get_children(); $nb_children = count($children); if ($nb_children > 0) { foreach ($children as $child) { $result['children'][] = $child->get_template_data($alike, $dlike, $thread_level + 1); } // Collapse if ($nb_children > 2 || $thread_level > 1) { $result['children'][0]['comment_firstcollapsed'] = true; $result['children'][0]['num_comments'] = sprintf(tt('%d comment', '%d comments', $total_children), $total_children); $result['children'][0]['hide_text'] = t('[+] show all'); if ($thread_level > 1) { $result['children'][$nb_children - 1]['comment_lastcollapsed'] = true; } else { $result['children'][$nb_children - 3]['comment_lastcollapsed'] = true; } } } $result['private'] = $item['item_private']; $result['toplevel'] = $this->is_toplevel() ? 'toplevel_item' : ''; if ($this->is_threaded()) { $result['flatten'] = false; $result['threaded'] = true; } else { $result['flatten'] = true; $result['threaded'] = false; } $t6 = dba_timer(); // profiler($t1,$t2,'t2'); // profiler($t2,$t3,'t3'); // profiler($t3,$t4,'t4'); // profiler($t4,$t5,'t5'); // profiler($t5,$t6,'t6'); // profiler($t1,$t6,'item total'); return $result; }