function get($update = 0, $load = false)
 {
     if (!local_channel()) {
         $_SESSION['return_url'] = \App::$query_string;
         return login(false);
     }
     if ($load) {
         $_SESSION['loadtime'] = datetime_convert();
     }
     $arr = array('query' => \App::$query_string);
     call_hooks('network_content_init', $arr);
     $channel = \App::get_channel();
     $item_normal = item_normal();
     $datequery = $datequery2 = '';
     $group = 0;
     $nouveau = false;
     $datequery = x($_GET, 'dend') && is_a_date_arg($_GET['dend']) ? notags($_GET['dend']) : '';
     $datequery2 = x($_GET, 'dbegin') && is_a_date_arg($_GET['dbegin']) ? notags($_GET['dbegin']) : '';
     $nouveau = x($_GET, 'new') ? intval($_GET['new']) : 0;
     $gid = x($_GET, 'gid') ? intval($_GET['gid']) : 0;
     $category = x($_REQUEST, 'cat') ? $_REQUEST['cat'] : '';
     $hashtags = x($_REQUEST, 'tag') ? $_REQUEST['tag'] : '';
     $verb = x($_REQUEST, 'verb') ? $_REQUEST['verb'] : '';
     $search = $_GET['search'] ? $_GET['search'] : '';
     if ($search) {
         if (strpos($search, '@') === 0) {
             $r = q("select abook_id from abook left join xchan on abook_xchan = xchan_hash where xchan_name = '%s' and abook_channel = %d limit 1", dbesc(substr($search, 1)), intval(local_channel()));
             if ($r) {
                 $_GET['cid'] = $r[0]['abook_id'];
                 $search = $_GET['search'] = '';
             }
         } elseif (strpos($search, '#') === 0) {
             $hashtags = substr($search, 1);
             $search = $_GET['search'] = '';
         }
     }
     if ($datequery) {
         $_GET['order'] = 'post';
     }
     // filter by collection (e.g. group)
     if ($gid) {
         $r = q("SELECT * FROM groups WHERE id = %d AND uid = %d LIMIT 1", intval($gid), intval(local_channel()));
         if (!$r) {
             if ($update) {
                 killme();
             }
             notice(t('No such group') . EOL);
             goaway(z_root() . '/network');
             // NOTREACHED
         }
         $group = $gid;
         $group_hash = $r[0]['hash'];
         $def_acl = array('allow_gid' => '<' . $r[0]['hash'] . '>');
     }
     $o = '';
     // if no tabs are selected, defaults to comments
     $cid = x($_GET, 'cid') ? intval($_GET['cid']) : 0;
     $star = x($_GET, 'star') ? intval($_GET['star']) : 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;
     $cmin = x($_GET, 'cmin') ? intval($_GET['cmin']) : 0;
     $cmax = x($_GET, 'cmax') ? intval($_GET['cmax']) : 99;
     $firehose = x($_GET, 'fh') ? intval($_GET['fh']) : 0;
     $file = x($_GET, 'file') ? $_GET['file'] : '';
     $deftag = '';
     if (x($_GET, 'search') || x($_GET, 'file')) {
         $nouveau = true;
     }
     if ($cid) {
         $r = q("SELECT abook_xchan FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1", intval($cid), intval(local_channel()));
         if (!$r) {
             if ($update) {
                 killme();
             }
             notice(t('No such channel') . EOL);
             goaway(z_root() . '/network');
             // NOTREACHED
         }
         if ($_GET['pf'] === '1') {
             $deftag = '@' . t('forum') . '+' . intval($cid) . '+';
         } else {
             $def_acl = array('allow_cid' => '<' . $r[0]['abook_xchan'] . '>');
         }
     }
     if (!$update) {
         $tabs = network_tabs();
         $o .= $tabs;
         // search terms header
         if ($search) {
             $o .= replace_macros(get_markup_template("section_title.tpl"), array('$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT, 'UTF-8')));
         }
         nav_set_selected('network');
         $channel_acl = array('allow_cid' => $channel['channel_allow_cid'], 'allow_gid' => $channel['channel_allow_gid'], 'deny_cid' => $channel['channel_deny_cid'], 'deny_gid' => $channel['channel_deny_gid']);
         $private_editing = ($group || $cid) && !intval($_GET['pf']) ? true : false;
         $x = array('is_owner' => true, 'allow_location' => intval(get_pconfig($channel['channel_id'], 'system', 'use_browser_location')) ? '1' : '', 'default_location' => $channel['channel_location'], 'nickname' => $channel['channel_address'], 'lockstate' => $private_editing || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid'] ? 'lock' : 'unlock', 'acl' => populate_acl($private_editing ? $def_acl : $channel_acl, true, \PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), 'bang' => $private_editing ? '!' : '', 'visitor' => true, 'profile_uid' => local_channel(), 'editor_autocomplete' => true, 'bbco_autocomplete' => 'bbcode', 'bbcode' => true);
         if ($deftag) {
             $x['pretext'] = $deftag;
         }
         $status_editor = status_editor($a, $x);
         $o .= $status_editor;
     }
     // We don't have to deal with ACL's on this page. You're looking at everything
     // that belongs to you, hence you can see all of it. We will filter by group if
     // desired.
     $sql_options = $star ? " and item_starred = 1 " : '';
     $sql_nets = '';
     $sql_extra = " AND `item`.`parent` IN ( SELECT `parent` FROM `item` WHERE item_thread_top = 1 {$sql_options} ) ";
     if ($group) {
         $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 ';
             info(t('Privacy group is empty'));
         }
         $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($group_hash) . '>%') . "' ) and id = parent {$item_normal} ) ";
         $x = group_rec_byhash(local_channel(), $group_hash);
         if ($x) {
             $title = replace_macros(get_markup_template("section_title.tpl"), array('$title' => t('Privacy group: ') . $x['name']));
         }
         $o = $tabs;
         $o .= $title;
         $o .= $status_editor;
     } elseif ($cid) {
         $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and abook_blocked = 0 limit 1", intval($cid), intval(local_channel()));
         if ($r) {
             $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true {$sql_options} AND uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($r[0]['abook_xchan']) . "' or owner_xchan = '" . dbesc($r[0]['abook_xchan']) . "' ) {$item_normal} ) ";
             $title = replace_macros(get_markup_template("section_title.tpl"), array('$title' => '<a href="' . zid($r[0]['xchan_url']) . '" ><img src="' . zid($r[0]['xchan_photo_s']) . '" alt="' . urlencode($r[0]['xchan_name']) . '" /></a> <a href="' . zid($r[0]['xchan_url']) . '" >' . $r[0]['xchan_name'] . '</a>'));
             $o = $tabs;
             $o .= $title;
             $o .= $status_editor;
         } else {
             notice(t('Invalid connection.') . EOL);
             goaway(z_root() . '/network');
         }
     }
     if (x($category)) {
         $sql_extra .= protect_sprintf(term_query('item', $category, TERM_CATEGORY));
     }
     if (x($hashtags)) {
         $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG));
     }
     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).
         if ($gid || $cid || $cmin || $cmax != 99 || $star || $liked || $conv || $spam || $nouveau || $list) {
             $firehose = 0;
         }
         $maxheight = get_pconfig(local_channel(), 'system', 'network_divmore_height');
         if (!$maxheight) {
             $maxheight = 400;
         }
         $o .= '<div id="live-network"></div>' . "\r\n";
         $o .= "<script> var profile_uid = " . local_channel() . "; var profile_page = " . \App::$pager['page'] . "; divmore_height = " . intval($maxheight) . "; </script>\r\n";
         \App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"), array('$baseurl' => z_root(), '$pgtype' => 'network', '$uid' => local_channel() ? local_channel() : '0', '$gid' => $gid ? $gid : '0', '$cid' => $cid ? $cid : '0', '$cmin' => $cmin ? $cmin : '0', '$cmax' => $cmax ? $cmax : '0', '$star' => $star ? $star : '0', '$liked' => $liked ? $liked : '0', '$conv' => $conv ? $conv : '0', '$spam' => $spam ? $spam : '0', '$fh' => $firehose ? $firehose : '0', '$nouveau' => $nouveau ? $nouveau : '0', '$wall' => '0', '$list' => x($_REQUEST, 'list') ? intval($_REQUEST['list']) : 0, '$page' => \App::$pager['page'] != 1 ? \App::$pager['page'] : 1, '$search' => $search ? $search : '', '$order' => $order, '$file' => $file, '$cats' => $category, '$tags' => $hashtags, '$dend' => $datequery, '$mid' => '', '$verb' => $verb, '$dbegin' => $datequery2));
     }
     $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;
     if (x($_GET, 'search')) {
         $search = escape_tags($_GET['search']);
         if (strpos($search, '#') === 0) {
             $sql_extra .= term_query('item', substr($search, 1), TERM_HASHTAG, TERM_COMMUNITYTAG);
         } else {
             $sql_extra .= sprintf(" AND item.body like '%s' ", dbesc(protect_sprintf('%' . $search . '%')));
         }
     }
     if ($verb) {
         $sql_extra .= sprintf(" AND item.verb like '%s' ", dbesc(protect_sprintf('%' . $verb . '%')));
     }
     if (strlen($file)) {
         $sql_extra .= term_query('item', $file, TERM_FILE);
     }
     if ($conv) {
         $sql_extra .= sprintf(" AND parent IN (SELECT distinct(parent) from item where ( author_xchan like '%s' or item_mentionsme = 1 )) ", dbesc(protect_sprintf($channel['channel_hash'])));
     }
     if ($update && !$load) {
         // only setup pagination on initial page view
         $pager_sql = '';
     } else {
         $itemspage = get_pconfig(local_channel(), 'system', 'itemspage');
         \App::set_pager_itemspage(intval($itemspage) ? $itemspage : 20);
         $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
     }
     if ($cmin != 0 || $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 ($cmax == 99) {
             $sql_nets .= " ( ";
         }
         $sql_nets .= "( abook.abook_closeness >= " . intval($cmin) . " ";
         $sql_nets .= " AND abook.abook_closeness <= " . intval($cmax) . " ) ";
         if ($cmax == 99) {
             $sql_nets .= " OR abook.abook_closeness IS NULL ) ";
         }
     }
     $abook_uids = " and abook.abook_channel = " . local_channel() . " ";
     if ($firehose && !get_config('system', 'disable_discover_tab')) {
         require_once 'include/identity.php';
         $sys = get_sys_channel();
         $uids = " and item.uid  = " . intval($sys['channel_id']) . " ";
         \App::$data['firehose'] = intval($sys['channel_id']);
     } else {
         $uids = " and item.uid = " . local_channel() . " ";
     }
     if (get_pconfig(local_channel(), 'system', 'network_list_mode')) {
         $page_mode = 'list';
     } else {
         $page_mode = 'client';
     }
     $simple_update = $update ? " and item_unseen = 1 " : '';
     // This fixes a very subtle bug so I'd better explain it. You wake up in the morning or return after a day
     // or three and look at your matrix page - after opening up your browser. The first page loads just as it
     // should. All of a sudden a few seconds later, page 2 will get inserted at the beginning of the page
     // (before the page 1 content). The update code is actually doing just what it's supposed
     // to, it's fetching posts that have the ITEM_UNSEEN bit set. But the reason that page 2 content is being
     // returned in an UPDATE is because you hadn't gotten that far yet - you're still on page 1 and everything
     // that we loaded for page 1 is now marked as seen. But the stuff on page 2 hasn't been. So... it's being
     // treated as "new fresh" content because it is unseen. We need to distinguish it somehow from content
     // which "arrived as you were reading page 1". We're going to do this
     // by storing in your session the current UTC time whenever you LOAD a network page, and only UPDATE items
     // which are both ITEM_UNSEEN and have "changed" since that time. Cross fingers...
     if ($update && $_SESSION['loadtime']) {
         $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime']) . "' )  OR item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime']) . "' ) ";
     }
     if ($load) {
         $simple_update = '';
     }
     if ($nouveau && $load) {
         // "New Item View" - show all items unthreaded in reverse created date order
         $items = q("SELECT item.*, item.id AS item_id, received FROM item\n\t\t\t\tleft join abook on ( item.owner_xchan = abook.abook_xchan {$abook_uids} )\n\t\t\t\tWHERE true {$uids} {$item_normal}\n\t\t\t\tand (abook.abook_blocked = 0 or abook.abook_flags is null)\n\t\t\t\t{$simple_update}\n\t\t\t\t{$sql_extra} {$sql_nets}\n\t\t\t\tORDER BY item.received DESC {$pager_sql} ");
         require_once 'include/items.php';
         xchan_query($items);
         $items = fetch_post_tags($items, true);
     } elseif ($update) {
         // Normal conversation view
         if ($order === 'post') {
             $ordering = "created";
         } else {
             $ordering = "commented";
         }
         if ($load) {
             // Fetch a page full of parent items for this page
             $r = q("SELECT distinct item.id AS item_id, {$ordering} FROM item\n\t\t\t\t\tleft join abook on ( item.owner_xchan = abook.abook_xchan {$abook_uids} )\n\t\t\t\t\tWHERE true {$uids} {$item_normal}\n\t\t\t\t\tAND item.parent = item.id\n\t\t\t\t\tand (abook.abook_blocked = 0 or abook.abook_flags is null)\n\t\t\t\t\t{$sql_extra3} {$sql_extra} {$sql_nets}\n\t\t\t\t\tORDER BY {$ordering} DESC {$pager_sql} ");
         } else {
             // this is an update
             $r = q("SELECT item.parent AS item_id FROM item\n\t\t\t\t\tleft join abook on ( item.owner_xchan = abook.abook_xchan {$abook_uids} )\n\t\t\t\t\tWHERE true {$uids} {$item_normal} {$simple_update}\n\t\t\t\t\tand (abook.abook_blocked = 0 or abook.abook_flags is null)\n\t\t\t\t\t{$sql_extra3} {$sql_extra} {$sql_nets} ");
             $_SESSION['loadtime'] = datetime_convert();
         }
         // Then fetch all the children of the parents that are on this page
         $parents_str = '';
         $update_unseen = '';
         if ($r) {
             $parents_str = ids_to_querystr($r, 'item_id');
             $items = q("SELECT item.*, item.id AS item_id FROM item\n\t\t\t\t\tWHERE true {$uids} {$item_normal}\n\t\t\t\t\tAND item.parent IN ( %s )\n\t\t\t\t\t{$sql_extra} ", dbesc($parents_str));
             xchan_query($items, true, $firehose ? local_channel() : 0);
             $items = fetch_post_tags($items, true);
             $items = conv_sort($items, $ordering);
         } else {
             $items = array();
         }
         if ($page_mode === 'list') {
             /**
              * in "list mode", only mark the parent item and any like activities as "seen". 
              * We won't distinguish between comment likes and post likes. The important thing
              * is that the number of unseen comments will be accurate. The SQL to separate the
              * comment likes could also get somewhat hairy. 
              */
             if ($parents_str) {
                 $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )";
                 $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) ";
             }
         } else {
             if ($parents_str) {
                 $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )";
             }
         }
     }
     if ($update_unseen && !$firehose) {
         $r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d {$update_unseen} ", intval(local_channel()));
     }
     $mode = $nouveau ? 'network-new' : 'network';
     $o .= conversation($a, $items, $mode, $update, $page_mode);
     if ($items && !$update) {
         $o .= alt_pager($a, count($items));
     }
     return $o;
 }
 function get()
 {
     if (!\App::$profile) {
         notice(t('Requested profile is not available.') . EOL);
         \App::$error = 404;
         return;
     }
     $which = argv(1);
     $uid = local_channel();
     $owner = 0;
     $channel = null;
     $observer = \App::get_observer();
     $channel = \App::get_channel();
     if (\App::$is_sys && is_site_admin()) {
         $sys = get_sys_channel();
         if ($sys && intval($sys['channel_id'])) {
             $uid = $owner = intval($sys['channel_id']);
             $channel = $sys;
             $observer = $sys;
         }
     }
     if (!$owner) {
         // Figure out who the page owner is.
         $r = q("select channel_id from channel where channel_address = '%s'", dbesc($which));
         if ($r) {
             $owner = intval($r[0]['channel_id']);
         }
     }
     $ob_hash = $observer ? $observer['xchan_hash'] : '';
     if (!perm_is_allowed($owner, $ob_hash, 'write_pages')) {
         notice(t('Permission denied.') . EOL);
         return;
     }
     $is_owner = $uid && $uid == $owner ? true : false;
     $o = '';
     // Figure out which post we're editing
     $post_id = argc() > 2 ? intval(argv(2)) : 0;
     if (!$post_id) {
         notice(t('Item not found') . EOL);
         return;
     }
     $ob_hash = $observer ? $observer['xchan_hash'] : '';
     $perms = get_all_perms($owner, $ob_hash);
     if (!$perms['write_pages']) {
         notice(t('Permission denied.') . EOL);
         return;
     }
     // We've already figured out which item we want and whose copy we need,
     // so we don't need anything fancy here
     $sql_extra = item_permissions_sql($owner);
     $itm = q("SELECT * FROM `item` WHERE `id` = %d and uid = %s {$sql_extra} LIMIT 1", intval($post_id), intval($owner));
     if (!$itm) {
         notice(t('Permission denied.') . EOL);
         return;
     }
     if (intval($itm[0]['item_obscured'])) {
         $key = get_config('system', 'prvkey');
         if ($itm[0]['title']) {
             $itm[0]['title'] = crypto_unencapsulate(json_decode_plus($itm[0]['title']), $key);
         }
         if ($itm[0]['body']) {
             $itm[0]['body'] = crypto_unencapsulate(json_decode_plus($itm[0]['body']), $key);
         }
     }
     $item_id = q("select * from item_id where service = 'WEBPAGE' and iid = %d limit 1", intval($itm[0]['id']));
     if ($item_id) {
         $page_title = $item_id[0]['sid'];
     }
     $mimetype = $itm[0]['mimetype'];
     if ($mimetype === 'application/x-php') {
         if (!$uid || $uid != $itm[0]['uid']) {
             notice(t('Permission denied.') . EOL);
             return;
         }
     }
     $layout = $itm[0]['layout_mid'];
     $tpl = get_markup_template("jot.tpl");
     $rp = 'webpages/' . $which;
     $x = array('nickname' => $channel['channel_address'], 'bbco_autocomplete' => $mimetype == 'text/bbcode' ? 'bbcode' : '', 'return_path' => $rp, 'webpage' => ITEM_TYPE_WEBPAGE, 'ptlabel' => t('Page link'), 'pagetitle' => $page_title, 'writefiles' => $mimetype == 'text/bbcode' ? perm_is_allowed($owner, get_observer_hash(), 'write_storage') : false, 'button' => t('Edit'), 'weblink' => $mimetype == 'text/bbcode' ? t('Insert web link') : false, 'hide_location' => true, 'hide_voting' => true, 'ptyp' => $itm[0]['type'], 'body' => undo_post_tagging($itm[0]['body']), 'post_id' => $post_id, 'visitor' => $is_owner ? true : false, 'acl' => populate_acl($itm[0], false, \PermissionDescription::fromGlobalPermission('view_pages')), 'showacl' => $is_owner ? true : false, 'mimetype' => $mimetype, 'mimeselect' => true, 'layout' => $layout, 'layoutselect' => true, 'title' => htmlspecialchars($itm[0]['title'], ENT_COMPAT, 'UTF-8'), 'lockstate' => strlen($itm[0]['allow_cid']) || strlen($itm[0]['allow_gid']) || strlen($itm[0]['deny_cid']) || strlen($itm[0]['deny_gid']) ? 'lock' : 'unlock', 'profile_uid' => intval($owner), 'bbcode' => $mimetype == 'text/bbcode' ? true : false);
     $editor = status_editor($a, $x);
     $o .= replace_macros(get_markup_template('edpost_head.tpl'), array('$title' => t('Edit Webpage'), '$delete' => $itm[0]['author_xchan'] === $ob_hash || $itm[0]['owner_xchan'] === $ob_hash ? t('Delete') : false, '$editor' => $editor, '$id' => $itm[0]['id']));
     return $o;
 }
 function get($update = 0, $load = false)
 {
     if ($load) {
         $_SESSION['loadtime'] = datetime_convert();
     }
     $checkjs = new \Zotlabs\Web\CheckJS(1);
     $category = $datequery = $datequery2 = '';
     $mid = x($_REQUEST, 'mid') ? $_REQUEST['mid'] : '';
     $datequery = x($_GET, 'dend') && is_a_date_arg($_GET['dend']) ? notags($_GET['dend']) : '';
     $datequery2 = x($_GET, 'dbegin') && is_a_date_arg($_GET['dbegin']) ? notags($_GET['dbegin']) : '';
     if (observer_prohibited(true)) {
         return login();
     }
     $category = x($_REQUEST, 'cat') ? $_REQUEST['cat'] : '';
     $hashtags = x($_REQUEST, 'tag') ? $_REQUEST['tag'] : '';
     $groups = array();
     $o = '';
     if ($update) {
         // Ensure we've got a profile owner if updating.
         \App::$profile['profile_uid'] = \App::$profile_uid = $update;
     } else {
         if (\App::$profile['profile_uid'] == local_channel()) {
             nav_set_selected('home');
         }
     }
     $is_owner = local_channel() && \App::$profile['profile_uid'] == local_channel() ? true : false;
     $channel = \App::get_channel();
     $observer = \App::get_observer();
     $ob_hash = $observer ? $observer['xchan_hash'] : '';
     $perms = get_all_perms(\App::$profile['profile_uid'], $ob_hash);
     if (!$perms['view_stream']) {
         // We may want to make the target of this redirect configurable
         if ($perms['view_profile']) {
             notice(t('Insufficient permissions.  Request redirected to profile page.') . EOL);
             goaway(z_root() . "/profile/" . \App::$profile['channel_address']);
         }
         notice(t('Permission denied.') . EOL);
         return;
     }
     if (!$update) {
         $o .= profile_tabs($a, $is_owner, \App::$profile['channel_address']);
         $o .= common_friends_visitor_widget(\App::$profile['profile_uid']);
         if ($channel && $is_owner) {
             $channel_acl = array('allow_cid' => $channel['channel_allow_cid'], 'allow_gid' => $channel['channel_allow_gid'], 'deny_cid' => $channel['channel_deny_cid'], 'deny_gid' => $channel['channel_deny_gid']);
         } else {
             $channel_acl = array();
         }
         if ($perms['post_wall']) {
             $x = array('is_owner' => $is_owner, 'allow_location' => ($is_owner || $observer) && intval(get_pconfig(\App::$profile['profile_uid'], 'system', 'use_browser_location')) ? true : false, 'default_location' => $is_owner ? \App::$profile['channel_location'] : '', 'nickname' => \App::$profile['channel_address'], 'lockstate' => strlen(\App::$profile['channel_allow_cid']) || strlen(\App::$profile['channel_allow_gid']) || strlen(\App::$profile['channel_deny_cid']) || strlen(\App::$profile['channel_deny_gid']) ? 'lock' : 'unlock', 'acl' => $is_owner ? populate_acl($channel_acl, true, \PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : '', 'showacl' => $is_owner ? 'yes' : '', 'bang' => '', 'visitor' => $is_owner || $observer ? true : false, 'profile_uid' => \App::$profile['profile_uid'], 'editor_autocomplete' => true, 'bbco_autocomplete' => 'bbcode', 'bbcode' => true);
             $o .= status_editor($a, $x);
         }
     }
     /**
      * Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups
      */
     $item_normal = item_normal();
     $sql_extra = item_permissions_sql(\App::$profile['profile_uid']);
     if (get_pconfig(\App::$profile['profile_uid'], 'system', 'channel_list_mode') && !$mid) {
         $page_mode = 'list';
     } else {
         $page_mode = 'client';
     }
     $abook_uids = " and abook.abook_channel = " . intval(\App::$profile['profile_uid']) . " ";
     $simple_update = $update ? " AND item_unseen = 1 " : '';
     \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string) . '" title="oembed" />' . "\r\n";
     if ($update && $_SESSION['loadtime']) {
         $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime']) . "' )  OR item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime']) . "' ) ";
     }
     if ($load) {
         $simple_update = '';
     }
     if ($update && !$load) {
         if ($mid) {
             $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d {$item_normal}\n\t\t\t\t\tAND item_wall = 1 AND item_unseen = 1 {$sql_extra} limit 1", dbesc($mid . '%'), intval(\App::$profile['profile_uid']));
         } else {
             $r = q("SELECT distinct parent AS `item_id`, created from item\n\t\t\t\t\tleft join abook on ( item.owner_xchan = abook.abook_xchan {$abook_uids} )\n\t\t\t\t\tWHERE uid = %d {$item_normal}\n\t\t\t\t\tAND item_wall = 1 {$simple_update}\n\t\t\t\t\tAND (abook.abook_blocked = 0 or abook.abook_flags is null)\n\t\t\t\t\t{$sql_extra}\n\t\t\t\t\tORDER BY created DESC", intval(\App::$profile['profile_uid']));
             $_SESSION['loadtime'] = datetime_convert();
         }
     } else {
         if (x($category)) {
             $sql_extra .= protect_sprintf(term_query('item', $category, TERM_CATEGORY));
         }
         if (x($hashtags)) {
             $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG));
         }
         if ($datequery) {
             $sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery))));
         }
         if ($datequery2) {
             $sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery2))));
         }
         $itemspage = get_pconfig(local_channel(), 'system', 'itemspage');
         \App::set_pager_itemspage(intval($itemspage) ? $itemspage : 20);
         $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
         if ($load || $checkjs->disabled()) {
             if ($mid) {
                 $r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d {$item_normal}\n\t\t\t\t\t\tAND item_wall = 1 {$sql_extra} limit 1", dbesc($mid), intval(\App::$profile['profile_uid']));
                 if (!$r) {
                     notice(t('Permission denied.') . EOL);
                 }
             } else {
                 $r = q("SELECT distinct id AS item_id, created FROM item \n\t\t\t\t\t\tleft join abook on item.author_xchan = abook.abook_xchan\n\t\t\t\t\t\tWHERE uid = %d {$item_normal}\n\t\t\t\t\t\tAND item_wall = 1 and item_thread_top = 1\n\t\t\t\t\t\tAND (abook_blocked = 0 or abook.abook_flags is null)\n\t\t\t\t\t\t{$sql_extra} {$sql_extra2}\n\t\t\t\t\t\tORDER BY created DESC {$pager_sql} ", intval(\App::$profile['profile_uid']));
             }
         } else {
             $r = array();
         }
     }
     if ($r) {
         $parents_str = ids_to_querystr($r, 'item_id');
         $items = q("SELECT `item`.*, `item`.`id` AS `item_id` \n\t\t\t\tFROM `item`\n\t\t\t\tWHERE `item`.`uid` = %d {$item_normal}\n\t\t\t\tAND `item`.`parent` IN ( %s )\n\t\t\t\t{$sql_extra} ", intval(\App::$profile['profile_uid']), dbesc($parents_str));
         xchan_query($items);
         $items = fetch_post_tags($items, true);
         $items = conv_sort($items, 'created');
         if ($load && $mid && !count($items)) {
             // This will happen if we don't have sufficient permissions
             // to view the parent item (or the item itself if it is toplevel)
             notice(t('Permission denied.') . EOL);
         }
     } else {
         $items = array();
     }
     if (!$update && !$load) {
         // 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.
         $maxheight = get_pconfig(\App::$profile['profile_uid'], 'system', 'channel_divmore_height');
         if (!$maxheight) {
             $maxheight = 400;
         }
         $o .= '<div id="live-channel"></div>' . "\r\n";
         $o .= "<script> var profile_uid = " . \App::$profile['profile_uid'] . "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . "; divmore_height = " . intval($maxheight) . "; </script>\r\n";
         \App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"), array('$baseurl' => z_root(), '$pgtype' => 'channel', '$uid' => \App::$profile['profile_uid'] ? \App::$profile['profile_uid'] : '0', '$gid' => '0', '$cid' => '0', '$cmin' => '0', '$cmax' => '0', '$star' => '0', '$liked' => '0', '$conv' => '0', '$spam' => '0', '$nouveau' => '0', '$wall' => '1', '$fh' => '0', '$page' => \App::$pager['page'] != 1 ? \App::$pager['page'] : 1, '$search' => '', '$order' => '', '$list' => x($_REQUEST, 'list') ? intval($_REQUEST['list']) : 0, '$file' => '', '$cats' => $category ? $category : '', '$tags' => $hashtags ? $hashtags : '', '$mid' => $mid, '$verb' => '', '$dend' => $datequery, '$dbegin' => $datequery2));
     }
     $update_unseen = '';
     if ($page_mode === 'list') {
         /**
          * in "list mode", only mark the parent item and any like activities as "seen". 
          * We won't distinguish between comment likes and post likes. The important thing
          * is that the number of unseen comments will be accurate. The SQL to separate the
          * comment likes could also get somewhat hairy. 
          */
         if ($parents_str) {
             $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )";
             $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) ";
         }
     } else {
         if ($parents_str) {
             $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )";
         }
     }
     if ($is_owner && $update_unseen) {
         $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d {$update_unseen}", intval(local_channel()));
     }
     if ($checkjs->disabled()) {
         $o .= conversation($a, $items, 'channel', $update, 'traditional');
     } else {
         $o .= conversation($a, $items, 'channel', $update, $page_mode);
     }
     if (!$update || $checkjs->disabled()) {
         $o .= alt_pager($a, count($items));
         if ($mid && $items[0]['title']) {
             \App::$page['title'] = $items[0]['title'] . " - " . \App::$page['title'];
         }
     }
     if ($mid) {
         $o .= '<div id="content-complete"></div>';
     }
     return $o;
 }
 function get()
 {
     if (argc() > 2 && argv(1) == 'ical') {
         $event_id = argv(2);
         require_once 'include/security.php';
         $sql_extra = permissions_sql(local_channel());
         $r = q("select * from event where event_hash = '%s' {$sql_extra} limit 1", dbesc($event_id));
         if ($r) {
             header('Content-type: text/calendar');
             header('content-disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"');
             echo ical_wrapper($r);
             killme();
         } else {
             notice(t('Event not found.') . EOL);
             return;
         }
     }
     if (!local_channel()) {
         notice(t('Permission denied.') . EOL);
         return;
     }
     nav_set_selected('all_events');
     if (argc() > 2 && argv(1) === 'ignore' && intval(argv(2))) {
         $r = q("update event set ignore = 1 where id = %d and uid = %d", intval(argv(2)), intval(local_channel()));
     }
     if (argc() > 2 && argv(1) === 'unignore' && intval(argv(2))) {
         $r = q("update event set ignore = 0 where id = %d and uid = %d", intval(argv(2)), intval(local_channel()));
     }
     $first_day = get_pconfig(local_channel(), 'system', 'cal_first_day');
     $first_day = $first_day ? $first_day : 0;
     $htpl = get_markup_template('event_head.tpl');
     \App::$page['htmlhead'] .= replace_macros($htpl, array('$baseurl' => z_root(), '$module_url' => '/events', '$modparams' => 1, '$lang' => \App::$language, '$first_day' => $first_day));
     $o = '';
     $channel = \App::get_channel();
     $mode = 'view';
     $y = 0;
     $m = 0;
     $ignored = x($_REQUEST, 'ignored') ? " and ignored = " . intval($_REQUEST['ignored']) . " " : '';
     // logger('args: ' . print_r(\App::$argv,true));
     if (argc() > 1) {
         if (argc() > 2 && argv(1) === 'add') {
             $mode = 'add';
             $item_id = intval(argv(2));
         }
         if (argc() > 2 && argv(1) === 'drop') {
             $mode = 'drop';
             $event_id = argv(2);
         }
         if (argc() > 2 && intval(argv(1)) && intval(argv(2))) {
             $mode = 'view';
             $y = intval(argv(1));
             $m = intval(argv(2));
         }
         if (argc() <= 2) {
             $mode = 'view';
             $event_id = argv(1);
         }
     }
     if ($mode === 'add') {
         event_addtocal($item_id, local_channel());
         killme();
     }
     if ($mode == 'view') {
         /* edit/create form */
         if ($event_id) {
             $r = q("SELECT * FROM `event` WHERE event_hash = '%s' AND `uid` = %d LIMIT 1", dbesc($event_id), intval(local_channel()));
             if (count($r)) {
                 $orig_event = $r[0];
             }
         }
         $channel = \App::get_channel();
         // Passed parameters overrides anything found in the DB
         if (!x($orig_event)) {
             $orig_event = array();
         }
         // In case of an error the browser is redirected back here, with these parameters filled in with the previous values
         /*
         if(x($_REQUEST,'nofinish')) $orig_event['nofinish'] = $_REQUEST['nofinish'];
         if(x($_REQUEST,'adjust')) $orig_event['adjust'] = $_REQUEST['adjust'];
         if(x($_REQUEST,'summary')) $orig_event['summary'] = $_REQUEST['summary'];
         if(x($_REQUEST,'description')) $orig_event['description'] = $_REQUEST['description'];
         if(x($_REQUEST,'location')) $orig_event['location'] = $_REQUEST['location'];
         if(x($_REQUEST,'start')) $orig_event['start'] = $_REQUEST['start'];
         if(x($_REQUEST,'finish')) $orig_event['finish'] = $_REQUEST['finish'];
         if(x($_REQUEST,'type')) $orig_event['type'] = $_REQUEST['type'];
         */
         $n_checked = x($orig_event) && $orig_event['nofinish'] ? ' checked="checked" ' : '';
         $a_checked = x($orig_event) && $orig_event['adjust'] ? ' checked="checked" ' : '';
         $t_orig = x($orig_event) ? $orig_event['summary'] : '';
         $d_orig = x($orig_event) ? $orig_event['description'] : '';
         $l_orig = x($orig_event) ? $orig_event['location'] : '';
         $eid = x($orig_event) ? $orig_event['id'] : 0;
         $event_xchan = x($orig_event) ? $orig_event['event_xchan'] : $channel['channel_hash'];
         $mid = x($orig_event) ? $orig_event['mid'] : '';
         if (!x($orig_event)) {
             $sh_checked = '';
         } else {
             $sh_checked = ($orig_event['allow_cid'] === '<' . $channel['channel_hash'] . '>' || !$orig_event['allow_cid']) && !$orig_event['allow_gid'] && !$orig_event['deny_cid'] && !$orig_event['deny_gid'] ? '' : ' checked="checked" ';
         }
         if ($orig_event['event_xchan']) {
             $sh_checked .= ' disabled="disabled" ';
         }
         $sdt = x($orig_event) ? $orig_event['start'] : 'now';
         $fdt = x($orig_event) ? $orig_event['finish'] : '+1 hour';
         $tz = date_default_timezone_get();
         if (x($orig_event)) {
             $tz = $orig_event['adjust'] ? date_default_timezone_get() : 'UTC';
         }
         $syear = datetime_convert('UTC', $tz, $sdt, 'Y');
         $smonth = datetime_convert('UTC', $tz, $sdt, 'm');
         $sday = datetime_convert('UTC', $tz, $sdt, 'd');
         $shour = datetime_convert('UTC', $tz, $sdt, 'H');
         $sminute = datetime_convert('UTC', $tz, $sdt, 'i');
         $stext = datetime_convert('UTC', $tz, $sdt);
         $stext = substr($stext, 0, 14) . "00:00";
         $fyear = datetime_convert('UTC', $tz, $fdt, 'Y');
         $fmonth = datetime_convert('UTC', $tz, $fdt, 'm');
         $fday = datetime_convert('UTC', $tz, $fdt, 'd');
         $fhour = datetime_convert('UTC', $tz, $fdt, 'H');
         $fminute = datetime_convert('UTC', $tz, $fdt, 'i');
         $ftext = datetime_convert('UTC', $tz, $fdt);
         $ftext = substr($ftext, 0, 14) . "00:00";
         $type = x($orig_event) ? $orig_event['type'] : 'event';
         $f = get_config('system', 'event_input_format');
         if (!$f) {
             $f = 'ymd';
         }
         $catsenabled = feature_enabled(local_channel(), 'categories');
         $category = '';
         if ($catsenabled && x($orig_event)) {
             $itm = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d limit 1", dbesc($orig_event['event_hash']), intval(local_channel()));
             $itm = fetch_post_tags($itm);
             if ($itm) {
                 $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY);
                 foreach ($cats as $cat) {
                     if (strlen($category)) {
                         $category .= ', ';
                     }
                     $category .= $cat['term'];
                 }
             }
         }
         require_once 'include/acl_selectors.php';
         $acl = new \Zotlabs\Access\AccessList($channel);
         $perm_defaults = $acl->get();
         $tpl = get_markup_template('event_form.tpl');
         $form = replace_macros($tpl, array('$post' => z_root() . '/events', '$eid' => $eid, '$type' => $type, '$xchan' => $event_xchan, '$mid' => $mid, '$event_hash' => $event_id, '$summary' => array('summary', $event_id ? t('Edit event title') : t('Event title'), $t_orig, t('Required'), '*'), '$catsenabled' => $catsenabled, '$placeholdercategory' => t('Categories (comma-separated list)'), '$c_text' => $event_id ? t('Edit Category') : t('Category'), '$category' => $category, '$required' => '<span class="required" title="' . t('Required') . '">*</span>', '$s_dsel' => datetimesel($f, new \DateTime(), \DateTime::createFromFormat('Y', $syear + 5), \DateTime::createFromFormat('Y-m-d H:i', "{$syear}-{$smonth}-{$sday} {$shour}:{$sminute}"), $event_id ? t('Edit start date and time') : t('Start date and time'), 'start_text', true, true, '', '', true, $first_day), '$n_text' => t('Finish date and time are not known or not relevant'), '$n_checked' => $n_checked, '$f_dsel' => datetimesel($f, new \DateTime(), \DateTime::createFromFormat('Y', $fyear + 5), \DateTime::createFromFormat('Y-m-d H:i', "{$fyear}-{$fmonth}-{$fday} {$fhour}:{$fminute}"), $event_id ? t('Edit finish date and time') : t('Finish date and time'), 'finish_text', true, true, 'start_text', '', false, $first_day), '$nofinish' => array('nofinish', t('Finish date and time are not known or not relevant'), $n_checked, '', array(t('No'), t('Yes')), 'onclick="enableDisableFinishDate();"'), '$adjust' => array('adjust', t('Adjust for viewer timezone'), $a_checked, t('Important for events that happen in a particular place. Not practical for global holidays.'), array(t('No'), t('Yes'))), '$a_text' => t('Adjust for viewer timezone'), '$d_text' => $event_id ? t('Edit Description') : t('Description'), '$d_orig' => $d_orig, '$l_text' => $event_id ? t('Edit Location') : t('Location'), '$l_orig' => $l_orig, '$t_orig' => $t_orig, '$sh_text' => t('Share this event'), '$sh_checked' => $sh_checked, '$share' => array('share', t('Share this event'), $sh_checked, '', array(t('No'), t('Yes'))), '$preview' => t('Preview'), '$permissions' => t('Permission settings'), '$acl' => $orig_event['event_xchan'] ? '' : populate_acl(x($orig_event) ? $orig_event : $perm_defaults, false, \PermissionDescription::fromGlobalPermission('view_stream')), '$submit' => t('Submit'), '$advanced' => t('Advanced Options')));
         /* end edit/create form */
         $thisyear = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y');
         $thismonth = datetime_convert('UTC', date_default_timezone_get(), 'now', 'm');
         if (!$y) {
             $y = intval($thisyear);
         }
         if (!$m) {
             $m = intval($thismonth);
         }
         $export = false;
         if (argc() === 4 && argv(3) === 'export') {
             $export = true;
         }
         // Put some limits on dates. The PHP date functions don't seem to do so well before 1900.
         // An upper limit was chosen to keep search engines from exploring links millions of years in the future.
         if ($y < 1901) {
             $y = 1900;
         }
         if ($y > 2099) {
             $y = 2100;
         }
         $nextyear = $y;
         $nextmonth = $m + 1;
         if ($nextmonth > 12) {
             $nextmonth = 1;
             $nextyear++;
         }
         $prevyear = $y;
         if ($m > 1) {
             $prevmonth = $m - 1;
         } else {
             $prevmonth = 12;
             $prevyear--;
         }
         $dim = get_dim($y, $m);
         $start = sprintf('%d-%d-%d %d:%d:%d', $y, $m, 1, 0, 0, 0);
         $finish = sprintf('%d-%d-%d %d:%d:%d', $y, $m, $dim, 23, 59, 59);
         if (argv(1) === 'json') {
             if (x($_GET, 'start')) {
                 $start = $_GET['start'];
             }
             if (x($_GET, 'end')) {
                 $finish = $_GET['end'];
             }
         }
         $start = datetime_convert('UTC', 'UTC', $start);
         $finish = datetime_convert('UTC', 'UTC', $finish);
         $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
         $adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
         if (x($_GET, 'id')) {
             $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan\n\t                                from event left join item on resource_id = event_hash where resource_type = 'event' and event.uid = %d and event.id = %d limit 1", intval(local_channel()), intval($_GET['id']));
         } elseif ($export) {
             $r = q("SELECT * from event where uid = %d\n\t\t\t\t\tAND (( `adjust` = 0 AND ( `finish` >= '%s' or nofinish = 1 ) AND `start` <= '%s' ) \n\t\t\t\t\tOR  (  `adjust` = 1 AND ( `finish` >= '%s' or nofinish = 1 ) AND `start` <= '%s' )) ", intval(local_channel()), dbesc($start), dbesc($finish), dbesc($adjust_start), dbesc($adjust_finish));
         } else {
             // fixed an issue with "nofinish" events not showing up in the calendar.
             // There's still an issue if the finish date crosses the end of month.
             // Noting this for now - it will need to be fixed here and in Friendica.
             // Ultimately the finish date shouldn't be involved in the query.
             $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan\n\t                              from event left join item on event_hash = resource_id \n\t\t\t\t\twhere resource_type = 'event' and event.uid = %d {$ignored} \n\t\t\t\t\tAND (( adjust = 0 AND ( finish >= '%s' or nofinish = 1 ) AND start <= '%s' ) \n\t\t\t\t\tOR  (  adjust = 1 AND ( finish >= '%s' or nofinish = 1 ) AND start <= '%s' )) ", intval(local_channel()), dbesc($start), dbesc($finish), dbesc($adjust_start), dbesc($adjust_finish));
         }
         $links = array();
         if ($r && !$export) {
             xchan_query($r);
             $r = fetch_post_tags($r, true);
             $r = sort_by_date($r);
         }
         if ($r) {
             foreach ($r as $rr) {
                 $j = $rr['adjust'] ? datetime_convert('UTC', date_default_timezone_get(), $rr['start'], 'j') : datetime_convert('UTC', 'UTC', $rr['start'], 'j');
                 if (!x($links, $j)) {
                     $links[$j] = z_root() . '/' . \App::$cmd . '#link-' . $j;
                 }
             }
         }
         $events = array();
         $last_date = '';
         $fmt = t('l, F j');
         if ($r) {
             foreach ($r as $rr) {
                 $j = $rr['adjust'] ? datetime_convert('UTC', date_default_timezone_get(), $rr['start'], 'j') : datetime_convert('UTC', 'UTC', $rr['start'], 'j');
                 $d = $rr['adjust'] ? datetime_convert('UTC', date_default_timezone_get(), $rr['start'], $fmt) : datetime_convert('UTC', 'UTC', $rr['start'], $fmt);
                 $d = day_translate($d);
                 $start = $rr['adjust'] ? datetime_convert('UTC', date_default_timezone_get(), $rr['start'], 'c') : datetime_convert('UTC', 'UTC', $rr['start'], 'c');
                 if ($rr['nofinish']) {
                     $end = null;
                 } else {
                     $end = $rr['adjust'] ? datetime_convert('UTC', date_default_timezone_get(), $rr['finish'], 'c') : datetime_convert('UTC', 'UTC', $rr['finish'], 'c');
                 }
                 $is_first = $d !== $last_date;
                 $last_date = $d;
                 $edit = local_channel() && $rr['author_xchan'] == get_observer_hash() ? array(z_root() . '/events/' . $rr['event_hash'] . '?expandform=1', t('Edit event'), '', '') : false;
                 $drop = array(z_root() . '/events/drop/' . $rr['event_hash'], t('Delete event'), '', '');
                 $title = strip_tags(html_entity_decode(bbcode($rr['summary']), ENT_QUOTES, 'UTF-8'));
                 if (!$title) {
                     list($title, $_trash) = explode("<br", bbcode($rr['desc']), 2);
                     $title = strip_tags(html_entity_decode($title, ENT_QUOTES, 'UTF-8'));
                 }
                 $html = format_event_html($rr);
                 $rr['desc'] = bbcode($rr['desc']);
                 $rr['location'] = bbcode($rr['location']);
                 $events[] = array('id' => $rr['id'], 'hash' => $rr['event_hash'], 'start' => $start, 'end' => $end, 'drop' => $drop, 'allDay' => false, 'title' => $title, 'j' => $j, 'd' => $d, 'edit' => $edit, 'is_first' => $is_first, 'item' => $rr, 'html' => $html, 'plink' => array($rr['plink'], t('Link to Source'), '', ''));
             }
         }
         if ($export) {
             header('Content-type: text/calendar');
             header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"');
             echo ical_wrapper($r);
             killme();
         }
         if (\App::$argv[1] === 'json') {
             echo json_encode($events);
             killme();
         }
         // links: array('href', 'text', 'extra css classes', 'title')
         if (x($_GET, 'id')) {
             $tpl = get_markup_template("event.tpl");
         } else {
             $tpl = get_markup_template("events-js.tpl");
         }
         $o = replace_macros($tpl, array('$baseurl' => z_root(), '$new_event' => array(z_root() . '/events', $event_id ? t('Edit Event') : t('Create Event'), '', ''), '$previus' => array(z_root() . "/events/{$prevyear}/{$prevmonth}", t('Previous'), '', ''), '$next' => array(z_root() . "/events/{$nextyear}/{$nextmonth}", t('Next'), '', ''), '$export' => array(z_root() . "/events/{$y}/{$m}/export", t('Export'), '', ''), '$calendar' => cal($y, $m, $links, ' eventcal'), '$events' => $events, '$upload' => t('Import'), '$submit' => t('Submit'), '$prev' => t('Previous'), '$next' => t('Next'), '$today' => t('Today'), '$form' => $form, '$expandform' => x($_GET, 'expandform') ? true : false));
         if (x($_GET, 'id')) {
             echo $o;
             killme();
         }
         return $o;
     }
     if ($mode === 'drop' && $event_id) {
         $r = q("SELECT * FROM `event` WHERE event_hash = '%s' AND `uid` = %d LIMIT 1", dbesc($event_id), intval(local_channel()));
         $sync_event = $r[0];
         if ($r) {
             $r = q("delete from event where event_hash = '%s' and uid = %d limit 1", dbesc($event_id), intval(local_channel()));
             if ($r) {
                 $r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d", dbesc($event_id), intval(local_channel()));
                 $sync_event['event_deleted'] = 1;
                 build_sync_packet(0, array('event' => array($sync_event)));
                 info(t('Event removed') . EOL);
             } else {
                 notice(t('Failed to remove event') . EOL);
             }
             goaway(z_root() . '/events');
         }
     }
 }
 function get()
 {
     // URLs:
     // photos/name
     // photos/name/album/xxxxx (xxxxx is album name)
     // photos/name/image/xxxxx
     if (observer_prohibited()) {
         notice(t('Public access denied.') . EOL);
         return;
     }
     $unsafe = array_key_exists('unsafe', $_REQUEST) && $_REQUEST['unsafe'] ? 1 : 0;
     require_once 'include/bbcode.php';
     require_once 'include/security.php';
     require_once 'include/conversation.php';
     if (!x(\App::$data, 'channel')) {
         notice(t('No photos selected') . EOL);
         return;
     }
     $ph = photo_factory('');
     $phototypes = $ph->supportedTypes();
     $_SESSION['photo_return'] = \App::$cmd;
     //
     // Parse arguments
     //
     $can_comment = perm_is_allowed(\App::$profile['profile_uid'], get_observer_hash(), 'post_comments');
     if (argc() > 3) {
         $datatype = argv(2);
         $datum = argv(3);
     } else {
         if (argc() > 2) {
             $datatype = argv(2);
             $datum = '';
         } else {
             $datatype = 'summary';
         }
     }
     if (argc() > 4) {
         $cmd = argv(4);
     } else {
         $cmd = 'view';
     }
     //
     // Setup permissions structures
     //
     $can_post = false;
     $visitor = 0;
     $owner_uid = \App::$data['channel']['channel_id'];
     $owner_aid = \App::$data['channel']['channel_account_id'];
     $observer = \App::get_observer();
     $can_post = perm_is_allowed($owner_uid, $observer['xchan_hash'], 'write_storage');
     $can_view = perm_is_allowed($owner_uid, $observer['xchan_hash'], 'view_storage');
     if (!$can_view) {
         notice(t('Access to this item is restricted.') . EOL);
         return;
     }
     $sql_extra = permissions_sql($owner_uid);
     $o = "";
     $o .= "<script> var profile_uid = " . \App::$profile['profile_uid'] . "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . "; </script>\r\n";
     // tabs
     $_is_owner = local_channel() && local_channel() == $owner_uid;
     $o .= profile_tabs($a, $_is_owner, \App::$data['channel']['channel_address']);
     /**
      * Display upload form
      */
     if ($can_post) {
         $uploader = '';
         $ret = array('post_url' => z_root() . '/photos/' . \App::$data['channel']['channel_address'], 'addon_text' => $uploader, 'default_upload' => true);
         call_hooks('photo_upload_form', $ret);
         /* Show space usage */
         $r = q("select sum(filesize) as total from photo where aid = %d and imgscale = 0 ", intval(\App::$data['channel']['channel_account_id']));
         $limit = engr_units_to_bytes(service_class_fetch(\App::$data['channel']['channel_id'], 'photo_upload_limit'));
         if ($limit !== false) {
             $usage_message = sprintf(t("%1\$.2f MB of %2\$.2f MB photo storage used."), $r[0]['total'] / 1024000, $limit / 1024000);
         } else {
             $usage_message = sprintf(t('%1$.2f MB photo storage used.'), $r[0]['total'] / 1024000);
         }
         if ($_is_owner) {
             $channel = \App::get_channel();
             $acl = new \Zotlabs\Access\AccessList($channel);
             $channel_acl = $acl->get();
             $lockstate = $acl->is_private() ? 'lock' : 'unlock';
         }
         $aclselect = $_is_owner ? populate_acl($channel_acl, false, \PermissionDescription::fromGlobalPermission('view_storage')) : '';
         // this is wrong but is to work around an issue with js_upload wherein it chokes if these variables
         // don't exist. They really should be set to a parseable representation of the channel's default permissions
         // which can be processed by getSelected()
         if (!$aclselect) {
             $aclselect = '<input id="group_allow" type="hidden" name="allow_gid[]" value="" /><input id="contact_allow" type="hidden" name="allow_cid[]" value="" /><input id="group_deny" type="hidden" name="deny_gid[]" value="" /><input id="contact_deny" type="hidden" name="deny_cid[]" value="" />';
         }
         $selname = $datum ? hex2bin($datum) : '';
         $albums = array_key_exists('albums', \App::$data) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'], \App::$data['observer']);
         if (!$selname) {
             $def_album = get_pconfig(\App::$data['channel']['channel_id'], 'system', 'photo_path');
             if ($def_album) {
                 $selname = filepath_macro($def_album);
                 $albums['album'][] = array('text' => $selname);
             }
         }
         $tpl = get_markup_template('photos_upload.tpl');
         $upload_form = replace_macros($tpl, array('$pagename' => t('Upload Photos'), '$sessid' => session_id(), '$usage' => $usage_message, '$nickname' => \App::$data['channel']['channel_address'], '$newalbum_label' => t('Enter an album name'), '$newalbum_placeholder' => t('or select an existing album (doubleclick)'), '$visible' => array('visible', t('Create a status post for this upload'), 0, '', array(t('No'), t('Yes')), 'onclick="showHideBodyTextarea();"'), '$caption' => array('description', t('Caption (optional):')), '$body' => array('body', t('Description (optional):'), '', 'Description will only appear in the status post'), '$albums' => $albums['albums'], '$selname' => $selname, '$permissions' => t('Permissions'), '$aclselect' => $aclselect, '$lockstate' => $lockstate, '$uploader' => $ret['addon_text'], '$default' => $ret['default_upload'] ? true : false, '$uploadurl' => $ret['post_url'], '$submit' => t('Submit')));
     }
     //
     // dispatch request
     //
     /*
      * Display a single photo album
      */
     if ($datatype === 'album') {
         if (strlen($datum)) {
             if (strlen($datum) & 1 || !ctype_xdigit($datum)) {
                 notice(t('Album name could not be decoded') . EOL);
                 logger('mod_photos: illegal album encoding: ' . $datum);
                 $datum = '';
             }
         }
         $album = $datum ? hex2bin($datum) : '';
         \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$cmd) . '" title="oembed" />' . "\r\n";
         $r = q("SELECT `resource_id`, max(`imgscale`) AS `imgscale` FROM `photo` WHERE `uid` = %d AND `album` = '%s' \n\t\t\t\tAND `imgscale` <= 4 and photo_usage IN ( %d, %d ) and is_nsfw = %d {$sql_extra} GROUP BY `resource_id`", intval($owner_uid), dbesc($album), intval(PHOTO_NORMAL), intval(PHOTO_PROFILE), intval($unsafe));
         if (count($r)) {
             \App::set_pager_total(count($r));
             \App::set_pager_itemspage(60);
         } else {
             goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address']);
         }
         if ($_GET['order'] === 'posted') {
             $order = 'ASC';
         } else {
             $order = 'DESC';
         }
         $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN\n\t\t\t\t\t(SELECT resource_id, max(imgscale) imgscale FROM photo WHERE uid = %d AND album = '%s' AND imgscale <= 4 AND photo_usage IN ( %d, %d ) and is_nsfw = %d {$sql_extra} GROUP BY resource_id) ph \n\t\t\t\t\tON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale)\n\t\t\t\tORDER BY created {$order} LIMIT %d OFFSET %d", intval($owner_uid), dbesc($album), intval(PHOTO_NORMAL), intval(PHOTO_PROFILE), intval($unsafe), intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
         //edit album name
         $album_edit = null;
         if ($album !== t('Profile Photos') && $album !== 'Profile Photos' && $album !== 'Contact Photos' && $album !== t('Contact Photos')) {
             if ($can_post) {
                 $album_e = $album;
                 $albums = array_key_exists('albums', \App::$data) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'], \App::$data['observer']);
                 // @fixme - syncronise actions with DAV
                 //				$edit_tpl = get_markup_template('album_edit.tpl');
                 //				$album_edit = replace_macros($edit_tpl,array(
                 //					'$nametext' => t('Enter a new album name'),
                 //					'$name_placeholder' => t('or select an existing one (doubleclick)'),
                 //					'$nickname' => \App::$data['channel']['channel_address'],
                 //					'$album' => $album_e,
                 //					'$albums' => $albums['albums'],
                 //					'$hexalbum' => bin2hex($album),
                 //					'$submit' => t('Submit'),
                 //					'$dropsubmit' => t('Delete Album')
                 //				));
             }
         }
         if ($_GET['order'] === 'posted') {
             $order = array(t('Show Newest First'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . bin2hex($album));
         } else {
             $order = array(t('Show Oldest First'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . bin2hex($album) . '?f=&order=posted');
         }
         $photos = array();
         if (count($r)) {
             $twist = 'rotright';
             foreach ($r as $rr) {
                 if ($twist == 'rotright') {
                     $twist = 'rotleft';
                 } else {
                     $twist = 'rotright';
                 }
                 $ext = $phototypes[$rr['mimetype']];
                 $imgalt_e = $rr['filename'];
                 $desc_e = $rr['description'];
                 $imagelink = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $rr['resource_id'] . ($_GET['order'] === 'posted' ? '?f=&order=posted' : '');
                 $photos[] = array('id' => $rr['id'], 'twist' => ' ' . $twist . rand(2, 4), 'link' => $imagelink, 'title' => t('View Photo'), 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' . $ext, 'alt' => $imgalt_e, 'desc' => $desc_e, 'ext' => $ext, 'hash' => $rr['resource_id'], 'unknown' => t('Unknown'));
             }
         }
         if ($_REQUEST['aj']) {
             if ($photos) {
                 $o = replace_macros(get_markup_template('photosajax.tpl'), array('$photos' => $photos, '$album_id' => bin2hex($album)));
             } else {
                 $o = '<div id="content-complete"></div>';
             }
             echo $o;
             killme();
         } else {
             $o .= "<script> var page_query = '" . $_GET['q'] . "'; var extra_args = '" . extra_query_args() . "' ; </script>";
             $tpl = get_markup_template('photo_album.tpl');
             $o .= replace_macros($tpl, array('$photos' => $photos, '$album' => $album, '$album_id' => bin2hex($album), '$album_edit' => array(t('Edit Album'), $album_edit), '$can_post' => $can_post, '$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/upload/' . bin2hex($album)), '$order' => $order, '$upload_form' => $upload_form, '$usage' => $usage_message));
         }
         if (!$photos && $_REQUEST['aj']) {
             $o .= '<div id="content-complete"></div>';
             echo $o;
             killme();
         }
         //		$o .= paginate($a);
         return $o;
     }
     /** 
      * Display one photo
      */
     if ($datatype === 'image') {
         \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$cmd) . '" title="oembed" />' . "\r\n";
         // fetch image, item containing image, then comments
         $ph = q("SELECT id,aid,uid,xchan,resource_id,created,edited,title,`description`,album,filename,mimetype,height,width,filesize,imgscale,photo_usage,is_nsfw,allow_cid,allow_gid,deny_cid,deny_gid FROM `photo` WHERE `uid` = %d AND `resource_id` = '%s' \n\t\t\t\t{$sql_extra} ORDER BY `imgscale` ASC ", intval($owner_uid), dbesc($datum));
         if (!$ph) {
             /* Check again - this time without specifying permissions */
             $ph = q("SELECT id FROM photo WHERE uid = %d AND resource_id = '%s' LIMIT 1", intval($owner_uid), dbesc($datum));
             if ($ph) {
                 notice(t('Permission denied. Access to this item may be restricted.') . EOL);
             } else {
                 notice(t('Photo not available') . EOL);
             }
             return;
         }
         $prevlink = '';
         $nextlink = '';
         if ($_GET['order'] === 'posted') {
             $order = 'ASC';
         } else {
             $order = 'DESC';
         }
         $prvnxt = q("SELECT `resource_id` FROM `photo` WHERE `album` = '%s' AND `uid` = %d AND `imgscale` = 0 \n\t\t\t\t{$sql_extra} ORDER BY `created` {$order} ", dbesc($ph[0]['album']), intval($owner_uid));
         if (count($prvnxt)) {
             for ($z = 0; $z < count($prvnxt); $z++) {
                 if ($prvnxt[$z]['resource_id'] == $ph[0]['resource_id']) {
                     $prv = $z - 1;
                     $nxt = $z + 1;
                     if ($prv < 0) {
                         $prv = count($prvnxt) - 1;
                     }
                     if ($nxt >= count($prvnxt)) {
                         $nxt = 0;
                     }
                     break;
                 }
             }
             $prevlink = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$prv]['resource_id'] . ($_GET['order'] === 'posted' ? '?f=&order=posted' : '');
             $nextlink = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$nxt]['resource_id'] . ($_GET['order'] === 'posted' ? '?f=&order=posted' : '');
         }
         if (count($ph) == 1) {
             $hires = $lores = $ph[0];
         }
         if (count($ph) > 1) {
             if ($ph[1]['imgscale'] == 2) {
                 // original is 640 or less, we can display it directly
                 $hires = $lores = $ph[0];
             } else {
                 $hires = $ph[0];
                 $lores = $ph[1];
             }
         }
         $album_link = z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . bin2hex($ph[0]['album']);
         $tools = Null;
         $lock = Null;
         if ($can_post && $ph[0]['uid'] == $owner_uid) {
             $tools = array('profile' => array(z_root() . '/profile_photo/use/' . $ph[0]['resource_id'], t('Use as profile photo')), 'cover' => array(z_root() . '/cover_photo/use/' . $ph[0]['resource_id'], t('Use as cover photo')));
         }
         // lockstate
         $lockstate = strlen($ph[0]['allow_cid']) || strlen($ph[0]['allow_gid']) || strlen($ph[0]['deny_cid']) || strlen($ph[0]['deny_gid']) ? array('lock', t('Private Photo')) : array('unlock', Null);
         \App::$page['htmlhead'] .= '<script>$(document).keydown(function(event) {' . "\n";
         if ($prevlink) {
             \App::$page['htmlhead'] .= 'if(event.ctrlKey && event.keyCode == 37) { event.preventDefault(); window.location.href = \'' . $prevlink . '\'; }' . "\n";
         }
         if ($nextlink) {
             \App::$page['htmlhead'] .= 'if(event.ctrlKey && event.keyCode == 39) { event.preventDefault(); window.location.href = \'' . $nextlink . '\'; }' . "\n";
         }
         \App::$page['htmlhead'] .= '});</script>';
         if ($prevlink) {
             $prevlink = array($prevlink, t('Previous'));
         }
         $photo = array('href' => z_root() . '/photo/' . $hires['resource_id'] . '-' . $hires['imgscale'] . '.' . $phototypes[$hires['mimetype']], 'title' => t('View Full Size'), 'src' => z_root() . '/photo/' . $lores['resource_id'] . '-' . $lores['imgscale'] . '.' . $phototypes[$lores['mimetype']] . '?f=&_u=' . datetime_convert('', '', '', 'ymdhis'));
         if ($nextlink) {
             $nextlink = array($nextlink, t('Next'));
         }
         // Do we have an item for this photo?
         $linked_items = q("SELECT * FROM item WHERE resource_id = '%s' and resource_type = 'photo' \n\t\t\t\t{$sql_extra} LIMIT 1", dbesc($datum));
         $map = null;
         if ($linked_items) {
             xchan_query($linked_items);
             $linked_items = fetch_post_tags($linked_items, true);
             $link_item = $linked_items[0];
             $item_normal = item_normal();
             $r = q("select * from item where parent_mid = '%s' \n\t\t\t\t\t{$item_normal} and uid = %d {$sql_extra} ", dbesc($link_item['mid']), intval($link_item['uid']));
             if ($r) {
                 xchan_query($r);
                 $r = fetch_post_tags($r, true);
                 $r = conv_sort($r, 'commented');
             }
             $tags = array();
             if ($link_item['term']) {
                 $cnt = 0;
                 foreach ($link_item['term'] as $t) {
                     $tags[$cnt] = array(0 => format_term_for_display($t));
                     if ($can_post && $ph[0]['uid'] == $owner_uid) {
                         $tags[$cnt][1] = 'tagrm/drop/' . $link_item['id'] . '/' . bin2hex($t['term']);
                         //?f=&item=' . $link_item['id'];
                         $tags[$cnt][2] = t('Remove');
                     }
                     $cnt++;
                 }
             }
             if (local_channel() && local_channel() == $link_item['uid']) {
                 q("UPDATE `item` SET item_unseen = 0 WHERE parent = %d and uid = %d and item_unseen = 1", intval($link_item['parent']), intval(local_channel()));
             }
             if ($link_item['coord']) {
                 $map = generate_map($link_item['coord']);
             }
         }
         //		logger('mod_photo: link_item' . print_r($link_item,true));
         // FIXME - remove this when we move to conversation module
         $r = $r[0]['children'];
         $edit = null;
         if ($can_post) {
             $album_e = $ph[0]['album'];
             $caption_e = $ph[0]['description'];
             $aclselect_e = $_is_owner ? populate_acl($ph[0], true, \PermissionDescription::fromGlobalPermission('view_storage')) : '';
             $albums = array_key_exists('albums', \App::$data) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'], \App::$data['observer']);
             $_SESSION['album_return'] = bin2hex($ph[0]['album']);
             $edit = array('edit' => t('Edit photo'), 'id' => $link_item['id'], 'rotatecw' => t('Rotate CW (right)'), 'rotateccw' => t('Rotate CCW (left)'), 'albums' => $albums['albums'], 'album' => $album_e, 'newalbum_label' => t('Enter a new album name'), 'newalbum_placeholder' => t('or select an existing one (doubleclick)'), 'nickname' => \App::$data['channel']['channel_address'], 'resource_id' => $ph[0]['resource_id'], 'capt_label' => t('Caption'), 'caption' => $caption_e, 'tag_label' => t('Add a Tag'), 'permissions' => t('Permissions'), 'aclselect' => $aclselect_e, 'lockstate' => $lockstate[0], 'help_tags' => t('Example: @bob, @Barbara_Jensen, @jim@example.com'), 'item_id' => count($linked_items) ? $link_item['id'] : 0, 'adult_enabled' => feature_enabled($owner_uid, 'adult_photo_flagging'), 'adult' => array('adult', t('Flag as adult in album view'), intval($ph[0]['is_nsfw']), ''), 'submit' => t('Submit'), 'delete' => t('Delete Photo'));
         }
         if (count($linked_items)) {
             $cmnt_tpl = get_markup_template('comment_item.tpl');
             $tpl = get_markup_template('photo_item.tpl');
             $return_url = \App::$cmd;
             $like_tpl = get_markup_template('like_noshare.tpl');
             $likebuttons = '';
             if ($can_post || $can_comment) {
                 $likebuttons = array('id' => $link_item['id'], 'likethis' => t("I like this (toggle)"), 'nolike' => t("I don't like this (toggle)"), 'share' => t('Share'), 'wait' => t('Please wait'));
             }
             $comments = '';
             if (!count($r)) {
                 if ($can_post || $can_comment) {
                     $commentbox = replace_macros($cmnt_tpl, array('$return_path' => '', '$mode' => 'photos', '$jsreload' => $return_url, '$type' => 'wall-comment', '$id' => $link_item['id'], '$parent' => $link_item['id'], '$profile_uid' => $owner_uid, '$mylink' => $observer['xchan_url'], '$mytitle' => t('This is you'), '$myphoto' => $observer['xchan_photo_s'], '$comment' => t('Comment'), '$submit' => t('Submit'), '$preview' => t('Preview'), '$ww' => '', '$feature_encrypt' => false));
                 }
             }
             $alike = array();
             $dlike = array();
             $like = '';
             $dislike = '';
             $conv_responses = array('like' => array('title' => t('Likes', 'title')), 'dislike' => array('title' => t('Dislikes', 'title')), 'agree' => array('title' => t('Agree', 'title')), 'disagree' => array('title' => t('Disagree', 'title')), 'abstain' => array('title' => t('Abstain', 'title')), 'attendyes' => array('title' => t('Attending', 'title')), 'attendno' => array('title' => t('Not attending', 'title')), 'attendmaybe' => array('title' => t('Might attend', 'title')));
             if ($r) {
                 foreach ($r as $item) {
                     builtin_activity_puller($item, $conv_responses);
                 }
                 $like_count = x($alike, $link_item['mid']) ? $alike[$link_item['mid']] : '';
                 $like_list = x($alike, $link_item['mid']) ? $alike[$link_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, $link_item['mid']) ? $dlike[$link_item['mid']] : '';
                 $dislike_list = x($dlike, $link_item['mid']) ? $dlike[$link_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 = '';
                 }
                 //}
                 $like = isset($alike[$link_item['mid']]) ? format_like($alike[$link_item['mid']], $alike[$link_item['mid'] . '-l'], 'like', $link_item['mid']) : '';
                 $dislike = isset($dlike[$link_item['mid']]) ? format_like($dlike[$link_item['mid']], $dlike[$link_item['mid'] . '-l'], 'dislike', $link_item['mid']) : '';
                 // display comments
                 foreach ($r as $item) {
                     $comment = '';
                     $template = $tpl;
                     $sparkle = '';
                     if ((activity_match($item['verb'], ACTIVITY_LIKE) || activity_match($item['verb'], ACTIVITY_DISLIKE)) && $item['id'] != $item['parent']) {
                         continue;
                     }
                     $redirect_url = z_root() . '/redir/' . $item['cid'];
                     $profile_url = zid($item['author']['xchan_url']);
                     $sparkle = '';
                     $profile_name = $item['author']['xchan_name'];
                     $profile_avatar = $item['author']['xchan_photo_m'];
                     $profile_link = $profile_url;
                     $drop = '';
                     if ($observer['xchan_hash'] === $item['author_xchan'] || $observer['xchan_hash'] === $item['owner_xchan']) {
                         $drop = replace_macros(get_markup_template('photo_drop.tpl'), array('$id' => $item['id'], '$delete' => t('Delete')));
                     }
                     $name_e = $profile_name;
                     $title_e = $item['title'];
                     unobscure($item);
                     $body_e = prepare_text($item['body'], $item['mimetype']);
                     $comments .= replace_macros($template, array('$id' => $item['id'], '$mode' => 'photos', '$profile_url' => $profile_link, '$name' => $name_e, '$thumb' => $profile_avatar, '$sparkle' => $sparkle, '$title' => $title_e, '$body' => $body_e, '$ago' => relative_date($item['created']), '$indent' => $item['parent'] != $item['id'] ? ' comment' : '', '$drop' => $drop, '$comment' => $comment));
                 }
                 if ($can_post || $can_comment) {
                     $commentbox = replace_macros($cmnt_tpl, array('$return_path' => '', '$jsreload' => $return_url, '$type' => 'wall-comment', '$id' => $link_item['id'], '$parent' => $link_item['id'], '$profile_uid' => $owner_uid, '$mylink' => $observer['xchan_url'], '$mytitle' => t('This is you'), '$myphoto' => $observer['xchan_photo_s'], '$comment' => t('Comment'), '$submit' => t('Submit'), '$ww' => ''));
                 }
             }
             $paginate = paginate($a);
         }
         $album_e = array($album_link, $ph[0]['album']);
         $like_e = $like;
         $dislike_e = $dislike;
         $response_verbs = array('like');
         if (feature_enabled($owner_uid, 'dislike')) {
             $response_verbs[] = 'dislike';
         }
         $responses = get_responses($conv_responses, $response_verbs, '', $link_item);
         $photo_tpl = get_markup_template('photo_view.tpl');
         $o .= replace_macros($photo_tpl, array('$id' => $ph[0]['id'], '$album' => $album_e, '$tools_label' => t('Photo Tools'), '$tools' => $tools, '$lock' => $lockstate[1], '$photo' => $photo, '$prevlink' => $prevlink, '$nextlink' => $nextlink, '$desc' => $ph[0]['description'], '$filename' => $ph[0]['filename'], '$unknown' => t('Unknown'), '$tag_hdr' => t('In This Photo:'), '$tags' => $tags, 'responses' => $responses, '$edit' => $edit, '$map' => $map, '$map_text' => t('Map'), '$likebuttons' => $likebuttons, '$like' => $like_e, '$dislike' => $dislike_e, '$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' => $dislike_count, '$dislike_list' => $dislike_list, '$dislike_list_part' => $dislike_list_part, '$dislike_button_label' => $dislike_button_label, '$modal_dismiss' => t('Close'), '$comments' => $comments, '$commentbox' => $commentbox, '$paginate' => $paginate));
         \App::$data['photo_html'] = $o;
         return $o;
     }
     // Default - show recent photos with upload link (if applicable)
     //$o = '';
     \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$cmd) . '" title="oembed" />' . "\r\n";
     $r = q("SELECT `resource_id`, max(`imgscale`) AS `imgscale` FROM `photo` WHERE `uid` = %d \n\t\t\tand photo_usage in ( %d, %d ) and is_nsfw = %d {$sql_extra} GROUP BY `resource_id`", intval(\App::$data['channel']['channel_id']), intval(PHOTO_NORMAL), intval(PHOTO_PROFILE), intval($unsafe));
     if ($r) {
         \App::set_pager_total(count($r));
         \App::set_pager_itemspage(60);
     }
     $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.album, p.imgscale, p.created FROM photo p \n\t\t\tINNER JOIN ( SELECT resource_id, max(imgscale) imgscale FROM photo \n\t\t\t\tWHERE uid = %d AND photo_usage IN ( %d, %d ) \n\t\t\t\tAND is_nsfw = %d {$sql_extra} group by resource_id ) ph \n\t\t\tON (p.resource_id = ph.resource_id and p.imgscale = ph.imgscale) \n\t\t\tORDER by p.created DESC LIMIT %d OFFSET %d", intval(\App::$data['channel']['channel_id']), intval(PHOTO_NORMAL), intval(PHOTO_PROFILE), intval($unsafe), intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
     $photos = array();
     if ($r) {
         $twist = 'rotright';
         foreach ($r as $rr) {
             if ($twist == 'rotright') {
                 $twist = 'rotleft';
             } else {
                 $twist = 'rotright';
             }
             $ext = $phototypes[$rr['mimetype']];
             if (\App::get_template_engine() === 'internal') {
                 $alt_e = template_escape($rr['filename']);
                 $name_e = template_escape($rr['album']);
             } else {
                 $alt_e = $rr['filename'];
                 $name_e = $rr['album'];
             }
             $photos[] = array('id' => $rr['id'], 'twist' => ' ' . $twist . rand(2, 4), 'link' => z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $rr['resource_id'], 'title' => t('View Photo'), 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . ($rr['imgscale'] == 6 ? 4 : $rr['imgscale']) . '.' . $ext, 'alt' => $alt_e, 'album' => array('link' => z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . bin2hex($rr['album']), 'name' => $name_e, 'alt' => t('View Album')));
         }
     }
     if ($_REQUEST['aj']) {
         if ($photos) {
             $o = replace_macros(get_markup_template('photosajax.tpl'), array('$photos' => $photos, '$album_id' => bin2hex(t('Recent Photos'))));
         } else {
             $o = '<div id="content-complete"></div>';
         }
         echo $o;
         killme();
     } else {
         $o .= "<script> var page_query = '" . $_GET['q'] . "'; var extra_args = '" . extra_query_args() . "' ; </script>";
         $tpl = get_markup_template('photos_recent.tpl');
         $o .= replace_macros($tpl, array('$title' => t('Recent Photos'), '$album_id' => bin2hex(t('Recent Photos')), '$can_post' => $can_post, '$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/upload'), '$photos' => $photos, '$upload_form' => $upload_form, '$usage' => $usage_message));
     }
     if (!$photos && $_REQUEST['aj']) {
         $o .= '<div id="content-complete"></div>';
         echo $o;
         killme();
     }
     //	paginate($a);
     return $o;
 }
 function get()
 {
     if (argc() > 1) {
         $which = argv(1);
     } else {
         notice(t('Requested profile is not available.') . EOL);
         \App::$error = 404;
         return;
     }
     $r = q("select * from channel where channel_address = '%s'", dbesc($which));
     if ($r) {
         $channel = $r[0];
         $owner = intval($r[0]['channel_id']);
     }
     $observer = \App::get_observer();
     $ob_hash = $observer ? $observer['xchan_hash'] : '';
     $perms = get_all_perms($owner, $ob_hash);
     if (!$perms['view_storage']) {
         notice(t('Permission denied.') . EOL);
         return;
     }
     // Since we have ACL'd files in the wild, but don't have ACL here yet, we
     // need to return for anyone other than the owner, despite the perms check for now.
     $is_owner = local_channel() && $owner == local_channel() ? true : false;
     if (!$is_owner) {
         info(t('Permission Denied.') . EOL);
         return;
     }
     if (argc() > 3 && argv(3) === 'delete') {
         if (!$perms['write_storage']) {
             notice(t('Permission denied.') . EOL);
             return;
         }
         $file = intval(argv(2));
         $r = q("SELECT hash FROM attach WHERE id = %d AND uid = %d LIMIT 1", dbesc($file), intval($owner));
         if (!$r) {
             notice(t('File not found.') . EOL);
             goaway(z_root() . '/cloud/' . $which);
         }
         $f = $r[0];
         $channel = \App::get_channel();
         $parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']);
         attach_delete($owner, $f['hash']);
         goaway($parentpath);
     }
     if (argc() > 3 && argv(3) === 'edit') {
         require_once 'include/acl_selectors.php';
         if (!$perms['write_storage']) {
             notice(t('Permission denied.') . EOL);
             return;
         }
         $file = intval(argv(2));
         $r = q("select id, uid, folder, filename, revision, flags, is_dir, os_storage, hash, allow_cid, allow_gid, deny_cid, deny_gid from attach where id = %d and uid = %d limit 1", intval($file), intval($owner));
         $f = $r[0];
         $channel = \App::get_channel();
         $cloudpath = get_cloudpath($f) . (intval($f['is_dir']) ? '?f=&davguest=1' : '');
         $parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']);
         $aclselect_e = populate_acl($f, false, \PermissionDescription::fromGlobalPermission('view_storage'));
         $is_a_dir = intval($f['is_dir']) ? true : false;
         $lockstate = $f['allow_cid'] || $f['allow_gid'] || $f['deny_cid'] || $f['deny_gid'] ? 'lock' : 'unlock';
         // Encode path that is used for link so it's a valid URL
         // Keep slashes as slashes, otherwise mod_rewrite doesn't work correctly
         $encoded_path = str_replace('%2F', '/', rawurlencode($cloudpath));
         $o = replace_macros(get_markup_template('attach_edit.tpl'), array('$header' => t('Edit file permissions'), '$file' => $f, '$cloudpath' => z_root() . '/' . $encoded_path, '$parentpath' => $parentpath, '$uid' => $channel['channel_id'], '$channelnick' => $channel['channel_address'], '$permissions' => t('Permissions'), '$aclselect' => $aclselect_e, '$lockstate' => $lockstate, '$permset' => t('Set/edit permissions'), '$recurse' => array('recurse', t('Include all files and sub folders'), 0, '', array(t('No'), t('Yes'))), '$backlink' => t('Return to file list'), '$isadir' => $is_a_dir, '$cpdesc' => t('Copy/paste this code to attach file to a post'), '$cpldesc' => t('Copy/paste this URL to link file from a web page'), '$submit' => t('Submit'), '$attach_btn_title' => t('Share this file'), '$link_btn_title' => t('Show URL to this file'), '$notify' => array('notify', t('Notify your contacts about this file'), 0, '', array(t('No'), t('Yes')))));
         echo $o;
         killme();
     }
     goaway(z_root() . '/cloud/' . $which);
 }
 function get()
 {
     if (!\App::$profile) {
         notice(t('Requested profile is not available.') . EOL);
         \App::$error = 404;
         return;
     }
     $which = argv(1);
     $_SESSION['return_url'] = \App::$query_string;
     $uid = local_channel();
     $owner = 0;
     $channel = null;
     $observer = \App::get_observer();
     $channel = \App::get_channel();
     if (\App::$is_sys && is_site_admin()) {
         $sys = get_sys_channel();
         if ($sys && intval($sys['channel_id'])) {
             $uid = $owner = intval($sys['channel_id']);
             $channel = $sys;
             $observer = $sys;
         }
     }
     if (!$owner) {
         // Figure out who the page owner is.
         $r = q("select channel_id from channel where channel_address = '%s'", dbesc($which));
         if ($r) {
             $owner = intval($r[0]['channel_id']);
         }
     }
     $ob_hash = $observer ? $observer['xchan_hash'] : '';
     $perms = get_all_perms($owner, $ob_hash);
     if (!$perms['write_pages']) {
         notice(t('Permission denied.') . EOL);
         return;
     }
     $mimetype = $_REQUEST['mimetype'] ? $_REQUEST['mimetype'] : get_pconfig($owner, 'system', 'page_mimetype');
     $layout = $_REQUEST['layout'] ? $_REQUEST['layout'] : get_pconfig($owner, 'system', 'page_layout');
     // Create a status editor (for now - we'll need a WYSIWYG eventually) to create pages
     // Nickname is set to the observers xchan, and profile_uid to the owner's.
     // This lets you post pages at other people's channels.
     if (!$channel && $uid && $uid == \App::$profile_uid) {
         $channel = \App::get_channel();
     }
     if ($channel) {
         $channel_acl = array('allow_cid' => $channel['channel_allow_cid'], 'allow_gid' => $channel['channel_allow_gid'], 'deny_cid' => $channel['channel_deny_cid'], 'deny_gid' => $channel['channel_deny_gid']);
     } else {
         $channel_acl = array();
     }
     $is_owner = $uid && $uid == $owner;
     $o = profile_tabs($a, $is_owner, \App::$profile['channel_address']);
     $x = array('webpage' => ITEM_TYPE_WEBPAGE, 'is_owner' => true, 'nickname' => \App::$profile['channel_address'], 'lockstate' => $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid'] ? 'lock' : 'unlock', 'acl' => $is_owner ? populate_acl($channel_acl, false, \PermissionDescription::fromGlobalPermission('view_pages')) : '', 'showacl' => $is_owner ? true : false, 'visitor' => true, 'hide_location' => true, 'hide_voting' => true, 'profile_uid' => intval($owner), 'mimetype' => $mimetype, 'mimeselect' => true, 'layout' => $layout, 'layoutselect' => true, 'expanded' => true, 'novoting' => true, 'bbco_autocomplete' => 'bbcode', 'bbcode' => true);
     if ($_REQUEST['title']) {
         $x['title'] = $_REQUEST['title'];
     }
     if ($_REQUEST['body']) {
         $x['body'] = $_REQUEST['body'];
     }
     if ($_REQUEST['pagetitle']) {
         $x['pagetitle'] = $_REQUEST['pagetitle'];
     }
     $editor = status_editor($a, $x);
     // Get a list of webpages.  We can't display all them because endless scroll makes that unusable,
     // so just list titles and an edit link.
     /** @TODO - this should be replaced with pagelist_widget */
     $sql_extra = item_permissions_sql($owner);
     $r = q("select * from item_id left join item on item_id.iid = item.id \n\t\t\twhere item_id.uid = %d and service = 'WEBPAGE' and item_type = %d {$sql_extra} order by item.created desc", intval($owner), intval(ITEM_TYPE_WEBPAGE));
     $pages = null;
     if ($r) {
         $pages = array();
         foreach ($r as $rr) {
             unobscure($rr);
             $lockstate = $rr['allow_cid'] || $rr['allow_gid'] || $rr['deny_cid'] || $rr['deny_gid'] ? 'lock' : 'unlock';
             $element_arr = array('type' => 'webpage', 'title' => $rr['title'], 'body' => $rr['body'], 'created' => $rr['created'], 'edited' => $rr['edited'], 'mimetype' => $rr['mimetype'], 'pagetitle' => $rr['sid'], 'mid' => $rr['mid'], 'layout_mid' => $rr['layout_mid']);
             $pages[$rr['iid']][] = array('url' => $rr['iid'], 'pagetitle' => $rr['sid'], 'title' => $rr['title'], 'created' => datetime_convert('UTC', date_default_timezone_get(), $rr['created']), 'edited' => datetime_convert('UTC', date_default_timezone_get(), $rr['edited']), 'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]', 'lockstate' => $lockstate);
         }
     }
     //Build the base URL for edit links
     $url = z_root() . '/editwebpage/' . $which;
     $o .= replace_macros(get_markup_template('webpagelist.tpl'), array('$listtitle' => t('Webpages'), '$baseurl' => $url, '$create' => t('Create'), '$edit' => t('Edit'), '$share' => t('Share'), '$delete' => t('Delete'), '$pages' => $pages, '$channel' => $which, '$editor' => $editor, '$view' => t('View'), '$preview' => t('Preview'), '$actions_txt' => t('Actions'), '$pagelink_txt' => t('Page Link'), '$title_txt' => t('Page Title'), '$created_txt' => t('Created'), '$edited_txt' => t('Edited')));
     return $o;
 }
Exemple #8
0
 function get()
 {
     $o = '';
     if (!local_channel()) {
         if (remote_channel()) {
             // redirect to your own site.
             // We can only do this with a GET request so you'll need to keep the text short or risk getting truncated
             // by the wretched beast called 'suhosin'. All the browsers now allow long GET requests, but suhosin
             // blocks them.
             $url = get_rpost_path(\App::get_observer());
             // make sure we're not looping to our own hub
             if ($url && !stristr($url, \App::get_hostname())) {
                 foreach ($_REQUEST as $key => $arg) {
                     $url .= '&' . $key . '=' . $arg;
                 }
                 goaway($url);
             }
         }
         // The login procedure is going to bugger our $_REQUEST variables
         // so save them in the session.
         if (array_key_exists('body', $_REQUEST)) {
             $_SESSION['rpost'] = $_REQUEST;
         }
         return login();
     }
     // If we have saved rpost session variables, but nothing in the current $_REQUEST, recover the saved variables
     if (!array_key_exists('body', $_REQUEST) && array_key_exists('rpost', $_SESSION)) {
         $_REQUEST = $_SESSION['rpost'];
         unset($_SESSION['rpost']);
     }
     if (array_key_exists('channel', $_REQUEST)) {
         $r = q("select channel_id from channel where channel_account_id = %d and channel_address = '%s' limit 1", intval(get_account_id()), dbesc($_REQUEST['channel']));
         if ($r) {
             require_once 'include/security.php';
             $change = change_channel($r[0]['channel_id']);
         }
     }
     if ($_REQUEST['remote_return']) {
         $_SESSION['remote_return'] = $_REQUEST['remote_return'];
     }
     if (argc() > 1 && argv(1) === 'return') {
         if ($_SESSION['remote_return']) {
             goaway($_SESSION['remote_return']);
         }
         goaway(z_root() . '/network');
     }
     $plaintext = true;
     //	if(feature_enabled(local_channel(),'richtext'))
     //		$plaintext = false;
     if (array_key_exists('type', $_REQUEST) && $_REQUEST['type'] === 'html') {
         require_once 'include/html2bbcode.php';
         $_REQUEST['body'] = html2bbcode($_REQUEST['body']);
     }
     $channel = \App::get_channel();
     $acl = new \Zotlabs\Access\AccessList($channel);
     $channel_acl = $acl->get();
     if ($_REQUEST['url']) {
         $x = z_fetch_url(z_root() . '/linkinfo?f=&url=' . urlencode($_REQUEST['url']));
         if ($x['success']) {
             $_REQUEST['body'] = $_REQUEST['body'] . $x['body'];
         }
     }
     $x = array('is_owner' => true, 'allow_location' => intval(get_pconfig($channel['channel_id'], 'system', 'use_browser_location')) ? '1' : '', 'default_location' => $channel['channel_location'], 'nickname' => $channel['channel_address'], 'lockstate' => $acl->is_private() ? 'lock' : 'unlock', 'acl' => populate_acl($channel_acl, true, \PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), 'bang' => '', 'visitor' => true, 'profile_uid' => local_channel(), 'title' => $_REQUEST['title'], 'body' => $_REQUEST['body'], 'attachment' => $_REQUEST['attachment'], 'source' => x($_REQUEST, 'source') ? strip_tags($_REQUEST['source']) : '', 'return_path' => 'rpost/return', 'bbco_autocomplete' => 'bbcode', 'bbcode' => true);
     $editor = status_editor($a, $x);
     $o .= replace_macros(get_markup_template('edpost_head.tpl'), array('$title' => t('Edit post'), '$editor' => $editor));
     return $o;
 }