function store_doc_file($s) { if (is_dir($s)) { return; } $item = array(); $sys = get_sys_channel(); $item['aid'] = 0; $item['uid'] = $sys['channel_id']; if (strpos($s, '.md')) { $mimetype = 'text/markdown'; } elseif (strpos($s, '.html')) { $mimetype = 'text/html'; } else { $mimetype = 'text/bbcode'; } require_once 'include/html2plain.php'; $item['body'] = html2plain(prepare_text(file_get_contents($s), $mimetype, true)); $item['mimetype'] = 'text/plain'; $item['plink'] = z_root() . '/' . str_replace('doc', 'help', $s); $item['owner_xchan'] = $item['author_xchan'] = $sys['channel_hash']; $item['item_type'] = ITEM_TYPE_DOC; $r = q("select item.* from item left join item_id on item.id = item_id.iid where service = 'docfile' and\n\t\tsid = '%s' and item_type = %d limit 1", dbesc($s), intval(ITEM_TYPE_DOC)); if ($r) { $item['id'] = $r[0]['id']; $item['mid'] = $item['parent_mid'] = $r[0]['mid']; $x = item_store_update($item); } else { $item['mid'] = $item['parent_mid'] = item_message_id(); $x = item_store($item); } if ($x['success']) { update_remote_id($sys, $x['item_id'], ITEM_TYPE_DOC, $s, 'docfile', 0, $item['mid']); } }
function init() { $result = array('success' => false); $mindate = $_REQUEST['mindate'] ? datetime_convert('UTC', 'UTC', $_REQUEST['mindate']) : ''; if (!$mindate) { $mindate = datetime_convert('UTC', 'UTC', 'now - 14 days'); } if (observer_prohibited()) { $result['message'] = 'Public access denied'; json_return_and_die($result); } $observer = \App::get_observer(); $channel_address = argc() > 1 ? argv(1) : ''; if ($channel_address) { $r = q("select channel_id, channel_name from channel where channel_address = '%s' and channel_removed = 0 limit 1", dbesc(argv(1))); } else { $x = get_sys_channel(); if ($x) { $r = array($x); } $mindate = datetime_convert('UTC', 'UTC', 'now - 14 days'); } if (!$r) { $result['message'] = 'Channel not found.'; json_return_and_die($result); } logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG); $result['messages'] = zot_feed($r[0]['channel_id'], $observer['xchan_hash'], array('mindate' => $mindate)); $result['success'] = true; json_return_and_die($result); }
function zotfeed_init(&$a) { $result = array('success' => false); $mindate = $_REQUEST['mindate'] ? datetime_convert('UTC', 'UTC', $_REQUEST['mindate']) : ''; if (!$mindate) { $mindate = datetime_convert('UTC', 'UTC', 'now - 1 month'); } if (get_config('system', 'block_public') && !get_account_id() && !remote_user()) { $result['message'] = 'Public access denied'; json_return_and_die($result); } $observer = $a->get_observer(); $channel_address = argc() > 1 ? argv(1) : ''; if ($channel_address) { $r = q("select channel_id, channel_name from channel where channel_address = '%s' and not (channel_pageflags & %d) limit 1", dbesc(argv(1)), intval(PAGE_REMOVED)); } else { $x = get_sys_channel(); if ($x) { $r = array($x); } } if (!$r) { $result['message'] = 'Channel not found.'; json_return_and_die($result); } logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG); $result['messages'] = zot_feed($r[0]['channel_id'], $observer['xchan_hash'], $mindate); $result['success'] = true; json_return_and_die($result); }
function __construct($req) { $this->ret = array('success' => false); $this->success = false; $this->test = array_key_exists('test', $req) ? intval($req['test']) : 0; $this->address = $req['auth']; $this->desturl = $req['dest']; $this->sec = $req['sec']; $this->version = $req['version']; $this->delegate = $req['delegate']; $c = get_sys_channel(); if (!$c) { logger('unable to obtain response (sys) channel'); reply_die('no local channels found.'); } $x = $this->GetHublocs($this->address); if ($x) { foreach ($x as $xx) { if ($this->Verify($c, $xx)) { break; } } } /** * @FIXME we really want to save the return_url in the session before we * visit rmagic. This does however prevent a recursion if you visit * rmagic directly, as it would otherwise send you back here again. * But z_root() probably isn't where you really want to go. */ if (strstr($this->desturl, z_root() . '/rmagic')) { goaway(z_root()); } $this->reply_die(); }
function diaspora_dispatch_public($msg) { $sys_disabled = true; if (!get_config('system', 'disable_discover_tab')) { $sys_disabled = get_config('system', 'disable_diaspora_discover_tab'); } $sys = $sys_disabled ? null : get_sys_channel(); // find everybody following or allowing this author $r = q("SELECT * from channel where channel_id in ( SELECT abook_channel from abook left join xchan on abook_xchan = xchan_hash WHERE xchan_network like '%%diaspora%%' and xchan_addr = '%s' ) and channel_removed = 0 ", dbesc($msg['author'])); // look for those following tags - we'll check tag validity for each specific channel later $y = q("select * from channel where channel_id in ( SELECT uid from pconfig where cat = 'diaspora' and k = 'followed_tags' and v != '') and channel_removed = 0 "); if (is_array($y) && is_array($r)) { $r = array_merge($r, $y); } // @FIXME we should also enumerate channels that allow postings by anybody if ($r) { foreach ($r as $rr) { logger('diaspora_public: delivering to: ' . $rr['channel_name'] . ' (' . $rr['channel_address'] . ') '); diaspora_dispatch($rr, $msg); } } else { if (!$sys) { logger('diaspora_public: no subscribers'); } } if ($sys) { $sys['system'] = true; logger('diaspora_public: delivering to sys.'); diaspora_dispatch($sys, $msg); } }
function viewsrc_content(&$a) { $o = ''; $sys = get_sys_channel(); $item_id = argc() > 1 ? intval(argv(1)) : 0; $json = argc() > 2 && argv(2) === 'json' ? true : false; if (!local_channel()) { notice(t('Permission denied.') . EOL); } if (!$item_id) { App::$error = 404; notice(t('Item not found.') . EOL); } $item_normal = item_normal(); if (local_channel() && $item_id) { $r = q("select id, item_flags, item_obscured, body from item where uid in (%d , %d) and id = %d {$item_normal} limit 1", intval(local_channel()), intval($sys['channel_id']), intval($item_id)); if ($r) { if (intval($r[0]['item_obscured'])) { $r[0]['body'] = crypto_unencapsulate(json_decode($r[0]['body'], true), get_config('system', 'prvkey')); } $o = $json ? json_encode($r[0]['body']) : str_replace("\n", '<br />', $r[0]['body']); } } if (is_ajax()) { print '<div><i class="icon-pencil"> ' . t('Source of Item') . ' ' . $r[0]['id'] . '</i></div>'; echo $o; killme(); } return $o; }
function viewsrc_content(&$a) { $o = ''; $sys = get_sys_channel(); $item_id = argc() > 1 ? intval(argv(1)) : 0; $json = argc() > 2 && argv(2) === 'json' ? true : false; if (!local_channel()) { notice(t('Permission denied.') . EOL); } if (!$item_id) { $a->error = 404; notice(t('Item not found.') . EOL); } if (local_channel() && $item_id) { $r = q("select item_flags, body from item where item_restrict = 0 and uid in (%d , %d) and id = %d limit 1", intval(local_channel()), intval($sys['channel_id']), intval($item_id)); if ($r) { if ($r[0]['item_flags'] & ITEM_OBSCURED) { $r[0]['body'] = crypto_unencapsulate(json_decode($r[0]['body'], true), get_config('system', 'prvkey')); } $o = $json ? json_encode($r[0]['body']) : str_replace("\n", '<br />', $r[0]['body']); } } if (is_ajax()) { echo $o; killme(); } 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; } // Now we've got a post and an owner, let's find out if we're allowed to edit it $ob_hash = $observer ? $observer['xchan_hash'] : ''; $perms = get_all_perms($owner, $ob_hash); if (!$perms['write_pages']) { notice(t('Permission denied.') . EOL); return; } $itm = q("SELECT * FROM `item` WHERE `id` = %d and uid = %s LIMIT 1", intval($post_id), intval($owner)); $item_id = q("select * from item_id where service = 'PDL' and iid = %d limit 1", intval($itm[0]['id'])); if ($item_id) { $layout_title = $item_id[0]['sid']; } $rp = 'layouts/' . $which; $x = array('webpage' => ITEM_TYPE_PDL, 'nickname' => $channel['channel_address'], 'editor_autocomplete' => true, 'bbco_autocomplete' => 'comanche', 'return_path' => $rp, 'button' => t('Edit'), 'hide_voting' => true, 'hide_future' => true, 'hide_expire' => true, 'hide_location' => true, 'hide_weblink' => true, 'hide_attach' => true, 'hide_preview' => true, 'ptyp' => $itm[0]['obj_type'], 'body' => undo_post_tagging($itm[0]['body']), 'post_id' => $post_id, 'title' => htmlspecialchars($itm[0]['title'], ENT_COMPAT, 'UTF-8'), 'pagetitle' => $layout_title, 'ptlabel' => t('Layout Name'), 'placeholdertitle' => t('Layout Description (Optional)'), 'showacl' => false, 'profile_uid' => intval($owner)); $editor = status_editor($a, $x); $o .= replace_macros(get_markup_template('edpost_head.tpl'), array('$title' => t('Edit Layout'), '$delete' => $itm[0]['author_xchan'] === $ob_hash || $itm[0]['owner_xchan'] === $ob_hash ? t('Delete') : false, '$id' => $itm[0]['id'], '$editor' => $editor)); 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 && $owner)) { notice(t('Item not found') . EOL); return; } $itm = q("SELECT * FROM `item` WHERE `id` = %d and uid = %s LIMIT 1", intval($post_id), intval($owner)); if ($itm) { $item_id = q("select * from item_id where service = 'BUILDBLOCK' and iid = %d limit 1", intval($itm[0]['id'])); if ($item_id) { $block_title = $item_id[0]['sid']; } } else { notice(t('Item not found') . EOL); return; } $mimetype = $itm[0]['mimetype']; $rp = 'blocks/' . $channel['channel_address']; $x = array('nickname' => $channel['channel_address'], 'bbco_autocomplete' => $mimetype == 'text/bbcode' ? 'bbcode' : 'comanche-block', 'return_path' => $rp, 'webpage' => ITEM_TYPE_BLOCK, 'ptlabel' => t('Block Name'), 'button' => t('Edit'), 'writefiles' => $mimetype == 'text/bbcode' ? perm_is_allowed($owner, get_observer_hash(), 'write_storage') : false, 'weblink' => $mimetype == 'text/bbcode' ? t('Insert web link') : false, 'hide_voting' => true, 'hide_future' => true, 'hide_location' => true, 'hide_expire' => true, 'showacl' => false, 'ptyp' => $itm[0]['type'], 'mimeselect' => true, 'mimetype' => $itm[0]['mimetype'], 'body' => undo_post_tagging($itm[0]['body']), 'post_id' => $post_id, 'visitor' => true, 'title' => htmlspecialchars($itm[0]['title'], ENT_COMPAT, 'UTF-8'), 'placeholdertitle' => t('Title (optional)'), 'pagetitle' => $block_title, 'profile_uid' => intval($channel['channel_id']), 'bbcode' => $mimetype == 'text/bbcode' ? true : false); $editor = status_editor($a, $x); $o .= replace_macros(get_markup_template('edpost_head.tpl'), array('$title' => t('Edit Block'), '$delete' => $itm[0]['author_xchan'] === $ob_hash || $itm[0]['owner_xchan'] === $ob_hash ? t('Delete') : false, '$id' => $itm[0]['id'], '$editor' => $editor)); return $o; }
function mitem_content(&$a) { $uid = local_channel(); $channel = $a->get_channel(); $observer = $a->get_observer(); $ob_hash = $observer ? $observer['xchan_hash'] : ''; if ($a->is_sys && is_site_admin()) { $sys = get_sys_channel(); $uid = intval($sys['channel_id']); $channel = $sys; $ob_hash = $sys['xchan_hash']; } if (!$uid) { notice(t('Permission denied.') . EOL); return ''; } if (argc() < 2 || !$a->data['menu']) { notice(t('Not found.') . EOL); return ''; } $m = menu_fetch($a->data['menu']['menu_name'], $uid, $ob_hash); $a->data['menu_item'] = $m; if (argc() == 2) { $r = q("select * from menu_item where mitem_menu_id = %d and mitem_channel_id = %d order by mitem_order asc, mitem_desc asc", intval($a->data['menu']['menu_id']), intval($uid)); $o .= replace_macros(get_markup_template('mitemlist.tpl'), array('$title' => t('Manage Menu Elements'), '$menuname' => $a->data['menu']['menu_name'], '$menudesc' => $a->data['menu']['menu_desc'], '$edmenu' => t('Edit menu'), '$menu_id' => $a->data['menu']['menu_id'], '$mlist' => $r, '$edit' => t('Edit element'), '$drop' => t('Drop element'), '$new' => t('New element'), '$hintmenu' => t('Edit this menu container'), '$hintnew' => t('Add menu element'), '$hintdrop' => t('Delete this menu item'), '$hintedit' => t('Edit this menu item'))); return $o; } if (argc() > 2) { if (argv(2) === 'new') { $perm_defaults = 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']); $o = replace_macros(get_markup_template('mitemedit.tpl'), array('$header' => t('New Menu Element'), '$menu_id' => $a->data['menu']['menu_id'], '$permissions' => t('Menu Item Permissions'), '$permdesc' => t("(click to open/close)"), '$aclselect' => populate_acl($perm_defaults, false), '$mitem_desc' => array('mitem_desc', t('Link text'), '', '', '*'), '$mitem_link' => array('mitem_link', t('URL of link'), '', '', '*'), '$usezid' => array('usezid', t('Use RedMatrix magic-auth if available'), true, ''), '$newwin' => array('newwin', t('Open link in new window'), false, ''), '$mitem_order' => array('mitem_order', t('Order in list'), '0', t('Higher numbers will sink to bottom of listing')), '$submit' => t('Create'))); return $o; } elseif (intval(argv(2))) { $m = q("select * from menu_item where mitem_id = %d and mitem_channel_id = %d limit 1", intval(argv(2)), intval($uid)); if (!$m) { notice(t('Menu item not found.') . EOL); goaway(z_root() . '/menu' . ($a->is_sys ? '?f=&sys=1' : '')); } $mitem = $m[0]; if (argc() == 4 && argv(3) == 'drop') { $r = menu_del_item($mitem['mitem_menu_id'], $uid, intval(argv(2))); if ($r) { info(t('Menu item deleted.') . EOL); } else { notice(t('Menu item could not be deleted.') . EOL); } goaway(z_root() . '/mitem/' . $mitem['mitem_menu_id'] . ($a->is_sys ? '?f=&sys=1' : '')); } else { // edit menu item $o = replace_macros(get_markup_template('mitemedit.tpl'), array('$header' => t('Edit Menu Element'), '$menu_id' => $a->data['menu']['menu_id'], '$permissions' => t('Menu Item Permissions'), '$permdesc' => t("(click to open/close)"), '$aclselect' => populate_acl($mitem, false), '$mitem_id' => intval(argv(2)), '$mitem_desc' => array('mitem_desc', t('Link text'), $mitem['mitem_desc'], '', '*'), '$mitem_link' => array('mitem_link', t('URL of link'), $mitem['mitem_link'], '', '*'), '$usezid' => array('usezid', t('Use RedMatrix magic-auth if available'), $mitem['mitem_flags'] & MENU_ITEM_ZID ? 1 : 0, ''), '$newwin' => array('newwin', t('Open link in new window'), $mitem['mitem_flags'] & MENU_ITEM_NEWWIN ? 1 : 0, ''), '$mitem_order' => array('mitem_order', t('Order in list'), $mitem['mitem_order'], t('Higher numbers will sink to bottom of listing')), '$submit' => t('Modify'))); return $o; } } } }
function get() { $uid = local_channel(); if (\App::$is_sys && is_site_admin()) { $sys = get_sys_channel(); $uid = intval($sys['channel_id']); } if (!$uid) { notice(t('Permission denied.') . EOL); return ''; } if (argc() == 1) { $channel = $sys ? $sys : \App::get_channel(); // list menus $x = menu_list($uid); if ($x) { for ($y = 0; $y < count($x); $y++) { $m = menu_fetch($x[$y]['menu_name'], $uid, get_observer_hash()); if ($m) { $x[$y]['element'] = '[element]' . base64url_encode(json_encode(menu_element($channel, $m))) . '[/element]'; } $x[$y]['bookmark'] = $x[$y]['menu_flags'] & MENU_BOOKMARK ? true : false; } } $create = replace_macros(get_markup_template('menuedit.tpl'), array('$menu_name' => array('menu_name', t('Menu Name'), '', t('Unique name (not visible on webpage) - required'), '*'), '$menu_desc' => array('menu_desc', t('Menu Title'), '', t('Visible on webpage - leave empty for no title'), ''), '$menu_bookmark' => array('menu_bookmark', t('Allow Bookmarks'), 0, t('Menu may be used to store saved bookmarks'), array(t('No'), t('Yes'))), '$submit' => t('Submit and proceed'), '$sys' => \App::$is_sys, '$display' => 'none')); $o = replace_macros(get_markup_template('menulist.tpl'), array('$title' => t('Menus'), '$create' => $create, '$menus' => $x, '$nametitle' => t('Menu Name'), '$desctitle' => t('Menu Title'), '$edit' => t('Edit'), '$drop' => t('Drop'), '$created' => t('Created'), '$edited' => t('Edited'), '$new' => t('New'), '$bmark' => t('Bookmarks allowed'), '$hintnew' => t('Create'), '$hintdrop' => t('Delete this menu'), '$hintcontent' => t('Edit menu contents'), '$hintedit' => t('Edit this menu'), '$sys' => \App::$is_sys)); return $o; } if (argc() > 1) { if (intval(argv(1))) { if (argc() == 3 && argv(2) == 'drop') { menu_sync_packet($uid, get_observer_hash(), intval(argv(1)), true); $r = menu_delete_id(intval(argv(1)), $uid); if (!$r) { notice(t('Menu could not be deleted.') . EOL); } goaway(z_root() . '/menu' . (\App::$is_sys ? '?f=&sys=1' : '')); } $m = menu_fetch_id(intval(argv(1)), $uid); if (!$m) { notice(t('Menu not found.') . EOL); return ''; } $o = replace_macros(get_markup_template('menuedit.tpl'), array('$header' => t('Edit Menu'), '$sys' => \App::$is_sys, '$menu_id' => intval(argv(1)), '$menu_edit_link' => 'mitem/' . intval(argv(1)) . (\App::$is_sys ? '?f=&sys=1' : ''), '$hintedit' => t('Add or remove entries to this menu'), '$editcontents' => t('Edit menu contents'), '$menu_name' => array('menu_name', t('Menu name'), $m['menu_name'], t('Must be unique, only seen by you'), '*'), '$menu_desc' => array('menu_desc', t('Menu title'), $m['menu_desc'], t('Menu title as seen by others'), ''), '$menu_bookmark' => array('menu_bookmark', t('Allow bookmarks'), $m['menu_flags'] & MENU_BOOKMARK ? 1 : 0, t('Menu may be used to store saved bookmarks'), array(t('No'), t('Yes'))), '$menu_system' => $m['menu_flags'] & MENU_SYSTEM ? 1 : 0, '$submit' => t('Submit and proceed'))); return $o; } else { notice(t('Not found.') . EOL); return; } } }
function diaspora_get_contact_by_handle($uid, $handle) { if (diaspora_is_blacklisted($handle)) { return false; } require_once 'include/channel.php'; $sys = get_sys_channel(); if ($sys && $sys['channel_id'] == $uid) { $r = q("SELECT * FROM xchan where xchan_addr = '%s' limit 1", dbesc($handle)); } else { $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where xchan_addr = '%s' and abook_channel = %d limit 1", dbesc($handle), intval($uid)); } return $r ? $r[0] : false; }
function menu_content(&$a) { $uid = local_channel(); if ($a->is_sys && is_site_admin()) { $sys = get_sys_channel(); $uid = intval($sys['channel_id']); } if (!$uid) { notice(t('Permission denied.') . EOL); return ''; } if (argc() == 1) { // list menus $x = menu_list($uid); if ($x) { for ($y = 0; $y < count($x); $y++) { $x[$y]['bookmark'] = $x[$y]['menu_flags'] & MENU_BOOKMARK ? true : false; } } $o = replace_macros(get_markup_template('menulist.tpl'), array('$title' => t('Manage Menus'), '$menus' => $x, '$edit' => t('Edit'), '$drop' => t('Drop'), '$new' => t('New'), '$bmark' => t('Bookmarks allowed'), '$hintnew' => t('Create a new menu'), '$hintdrop' => t('Delete this menu'), '$hintcontent' => t('Edit menu contents'), '$hintedit' => t('Edit this menu'))); return $o; } if (argc() > 1) { if (argv(1) === 'new') { $o = replace_macros(get_markup_template('menuedit.tpl'), array('$header' => t('New Menu'), '$menu_name' => array('menu_name', t('Menu name'), '', t('Must be unique, only seen by you'), '*'), '$menu_desc' => array('menu_desc', t('Menu title'), '', t('Menu title as seen by others'), ''), '$menu_bookmark' => array('menu_bookmark', t('Allow bookmarks'), 0, t('Menu may be used to store saved bookmarks'), ''), '$submit' => t('Create'))); return $o; } elseif (intval(argv(1))) { $m = menu_fetch_id(intval(argv(1)), $uid); if (!$m) { notice(t('Menu not found.') . EOL); return ''; } if (argc() == 3 && argv(2) == 'drop') { $r = menu_delete_id(intval(argv(1)), $uid); if ($r) { info(t('Menu deleted.') . EOL); } else { notice(t('Menu could not be deleted.') . EOL); } goaway(z_root() . '/menu' . ($a->is_sys ? '?f=&sys=1' : '')); } else { $o = replace_macros(get_markup_template('menuedit.tpl'), array('$header' => t('Edit Menu'), '$menu_id' => intval(argv(1)), '$hintedit' => t('Add or remove entries to this menu'), '$editcontents' => t('Edit menu contents'), '$menu_name' => array('menu_name', t('Menu name'), $m['menu_name'], t('Must be unique, only seen by you'), '*'), '$menu_desc' => array('menu_desc', t('Menu title'), $m['menu_desc'], t('Menu title as seen by others'), ''), '$menu_bookmark' => array('menu_bookmark', t('Allow bookmarks'), $m['menu_flags'] & MENU_BOOKMARK ? 1 : 0, t('Menu may be used to store saved bookmarks'), ''), '$menu_system' => $m['menu_flags'] & MENU_SYSTEM ? 1 : 0, '$submit' => t('Modify'))); return $o; } } else { notice(t('Not found.') . EOL); return; } } }
function pubsub_post(&$a) { $sys_disabled = true; if (!get_config('system', 'disable_discover_tab')) { $sys_disabled = get_config('system', 'disable_diaspora_discover_tab'); } $sys = $sys_disabled ? null : get_sys_channel(); if ($sys) { $sys['system'] = true; } $xml = file_get_contents('php://input'); logger('pubsub: feed arrived from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . App::$cmd); logger('pubsub: user-agent: ' . $_SERVER['HTTP_USER_AGENT']); logger('pubsub: data: ' . $xml, LOGGER_DATA); $nick = argc() > 1 ? escape_tags(trim(argv(1))) : ''; $contact_id = argc() > 2 ? intval(argv(2)) : 0; $channel = channelx_by_nick($nick); if (!$channel) { http_status_exit(200, 'OK'); } $importer_arr = array($channel); if ($sys) { $importer_arr[] = $sys; } foreach ($importer_arr as $channel) { if (!$channel['system']) { $connections = abook_connections($channel['channel_id'], ' and abook_id = ' . $contact_id); } else { $connections = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d", intval($contact_id)); } if ($connections) { $xchan = $connections[0]; } else { logger('connection ' . $contact_id . ' not found.'); continue; } if (!perm_is_allowed($channel['channel_id'], $xchan['xchan_hash'], 'send_stream') && !$channel['system']) { logger('permission denied.'); continue; } consume_feed($xml, $channel, $xchan, 1); consume_feed($xml, $channel, $xchan, 2); } http_status_exit(200, 'OK'); }
function expire_run($argv, $argc) { cli_startup(); $r = q("select id from item where (item_restrict & %d) and not (item_restrict & %d) and changed < UTC_TIMESTAMP() - INTERVAL 10 DAY", intval(ITEM_DELETED), intval(ITEM_PENDING_REMOVE)); if ($r) { foreach ($r as $rr) { drop_item($rr['id'], false, DROPITEM_PHASE2); } } // physically remove anything that has been deleted for more than two months $r = q("delete from item where ( item_restrict & %d ) and changed < UTC_TIMESTAMP() - INTERVAL 36 DAY", intval(ITEM_PENDING_REMOVE)); // make this optional as it could have a performance impact on large sites if (intval(get_config('system', 'optimize_items'))) { q("optimize table item"); } logger('expire: start', LOGGER_DEBUG); $r = q("SELECT channel_id, channel_address, channel_expire_days from channel where channel_expire_days != 0"); if ($r && count($r)) { foreach ($r as $rr) { logger('Expire: ' . $rr['channel_address'] . ' interval: ' . $rr['channel_expire_days'], LOGGER_DEBUG); item_expire($rr['channel_id'], $rr['channel_expire_days']); } } $x = get_sys_channel(); if ($x) { // this should probably just fetch the channel_expire_days from the sys channel, // but there's no convenient way to set it. $expire_days = get_config('externals', 'expire_days'); if ($expire_days === false) { $expire_days = 30; } if ($expire_days) { item_expire($x['channel_id'], $expire_days); } } return; }
function get($update = 0, $load = false) { $checkjs = new \Zotlabs\Web\CheckJS(1); if ($load) { $_SESSION['loadtime'] = datetime_convert(); } if (observer_prohibited()) { notice(t('Public access denied.') . EOL); return; } require_once "include/bbcode.php"; require_once 'include/security.php'; require_once 'include/conversation.php'; require_once 'include/acl_selectors.php'; require_once 'include/items.php'; \App::$page['htmlhead'] .= replace_macros(get_markup_template('display-head.tpl'), array()); if (argc() > 1 && argv(1) !== 'load') { $item_hash = argv(1); } if ($_REQUEST['mid']) { $item_hash = $_REQUEST['mid']; } if (!$item_hash) { \App::$error = 404; notice(t('Item not found.') . EOL); return; } $observer_is_owner = false; if (local_channel() && !$update) { $channel = \App::get_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']); $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' => $group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid'] ? 'lock' : 'unlock', 'acl' => populate_acl($channel_acl), 'permissions' => $channel_acl, 'bang' => '', 'visitor' => true, 'profile_uid' => local_channel(), 'return_path' => 'channel/' . $channel['channel_address'], 'expanded' => true, 'editor_autocomplete' => true, 'bbco_autocomplete' => 'bbcode', 'bbcode' => true); $o = '<div id="jot-popup">'; $o .= status_editor($a, $x); $o .= '</div>'; } // This page can be viewed by anybody so the query could be complicated // First we'll see if there is a copy of the item which is owned by us - if we're logged in locally. // If that fails (or we aren't logged in locally), // query an item in which the observer (if logged in remotely) has cid or gid rights // and if that fails, look for a copy of the post that has no privacy restrictions. // If we find the post, but we don't find a copy that we're allowed to look at, this fact needs to be reported. // find a copy of the item somewhere $target_item = null; $r = q("select id, uid, mid, parent_mid, item_type, item_deleted from item where mid like '%s' limit 1", dbesc($item_hash . '%')); if ($r) { $target_item = $r[0]; } $r = null; if ($target_item['item_type'] == ITEM_TYPE_WEBPAGE) { $x = q("select * from channel where channel_id = %d limit 1", intval($target_item['uid'])); $y = q("select * from iconfig left join item on iconfig.iid = item.id \n\t\t\t\twhere item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item.id = %d limit 1", intval($target_item['uid']), intval($target_item['id'])); if ($x && $y) { goaway(z_root() . '/page/' . $x[0]['channel_address'] . '/' . $y[0]['v']); } else { notice(t('Page not found.') . EOL); return ''; } } $simple_update = $update ? " AND item_unseen = 1 " : ''; 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) { $o .= '<div id="live-display"></div>' . "\r\n"; $o .= "<script> var profile_uid = " . (intval(local_channel()) ? local_channel() : -1) . "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . "; </script>\r\n"; \App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"), array('$baseurl' => z_root(), '$pgtype' => 'display', '$uid' => '0', '$gid' => '0', '$cid' => '0', '$cmin' => '0', '$cmax' => '99', '$star' => '0', '$liked' => '0', '$conv' => '0', '$spam' => '0', '$fh' => '0', '$nouveau' => '0', '$wall' => '0', '$page' => \App::$pager['page'] != 1 ? \App::$pager['page'] : 1, '$list' => x($_REQUEST, 'list') ? intval($_REQUEST['list']) : 0, '$search' => '', '$order' => '', '$file' => '', '$cats' => '', '$tags' => '', '$dend' => '', '$dbegin' => '', '$verb' => '', '$mid' => $item_hash)); } $observer_hash = get_observer_hash(); $item_normal = item_normal(); $sql_extra = public_permissions_sql($observer_hash); if ($update && $load || $checkjs->disabled()) { $updateable = false; $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start'])); if ($load || $checkjs->disabled()) { $r = null; require_once 'include/channel.php'; $sys = get_sys_channel(); $sysid = $sys['channel_id']; if (local_channel()) { $r = q("SELECT * from item\n\t\t\t\t\t\tWHERE uid = %d\n\t\t\t\t\t\tand mid = '%s'\n\t\t\t\t\t\t{$item_normal}\n\t\t\t\t\t\tlimit 1", intval(local_channel()), dbesc($target_item['parent_mid'])); if ($r) { $updateable = true; } } if ($r === null) { // in case somebody turned off public access to sys channel content using permissions // make that content unsearchable by ensuring the owner_xchan can't match if (!perm_is_allowed($sysid, $observer_hash, 'view_stream')) { $sysid = 0; } $r = q("SELECT * from item\n\t\t\t\t\t\tWHERE mid = '%s'\n\t\t\t\t\t\tAND (((( `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' \n\t\t\t\t\t\tAND `item`.`deny_gid` = '' AND item_private = 0 ) \n\t\t\t\t\t\tand owner_xchan in ( " . stream_perms_xchans($observer_hash ? PERMS_NETWORK | PERMS_PUBLIC : PERMS_PUBLIC) . " ))\n\t\t\t\t\t\tOR uid = %d )\n\t\t\t\t\t\t{$sql_extra} )\n\t\t\t\t\t\t{$item_normal}\n\t\t\t\t\t\tlimit 1", dbesc($target_item['parent_mid']), intval($sysid)); } } } elseif ($update && !$load) { $r = null; require_once 'include/channel.php'; $sys = get_sys_channel(); $sysid = $sys['channel_id']; if (local_channel()) { $r = q("SELECT * from item\n\t\t\t\t\tWHERE uid = %d\n\t\t\t\t\tand mid = '%s'\n\t\t\t\t\t{$item_normal}\n\t\t\t\t\t{$simple_update}\n\t\t\t\t\tlimit 1", intval(local_channel()), dbesc($target_item['parent_mid'])); if ($r) { $updateable = true; } } if ($r === null) { // in case somebody turned off public access to sys channel content using permissions // make that content unsearchable by ensuring the owner_xchan can't match if (!perm_is_allowed($sysid, $observer_hash, 'view_stream')) { $sysid = 0; } $r = q("SELECT * from item\n\t\t\t\t\tWHERE mid = '%s'\n\t\t\t\t\tAND (((( `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' \n\t\t\t\t\tAND `item`.`deny_gid` = '' AND item_private = 0 ) \n\t\t\t\t\tand owner_xchan in ( " . stream_perms_xchans($observer_hash ? PERMS_NETWORK | PERMS_PUBLIC : PERMS_PUBLIC) . " ))\n\t\t\t\t\tOR uid = %d )\n\t\t\t\t\t{$sql_extra} )\n\t\t\t\t\t{$item_normal}\n\t\t\t\t\t{$simple_update}\n\t\t\t\t\tlimit 1", dbesc($target_item['parent_mid']), intval($sysid)); } $_SESSION['loadtime'] = datetime_convert(); } else { $r = array(); } if ($r) { $parents_str = ids_to_querystr($r, 'id'); if ($parents_str) { $items = q("SELECT `item`.*, `item`.`id` AS `item_id` \n\t\t\t\t\tFROM `item`\n\t\t\t\t\tWHERE parent in ( %s ) {$item_normal} ", dbesc($parents_str)); xchan_query($items); $items = fetch_post_tags($items, true); $items = conv_sort($items, 'created'); } } else { $items = array(); } if ($checkjs->disabled()) { $o .= conversation($a, $items, 'display', $update, 'traditional'); if ($items[0]['title']) { \App::$page['title'] = $items[0]['title'] . " - " . \App::$page['title']; } } else { $o .= conversation($a, $items, 'display', $update, 'client'); } if ($updateable) { $x = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 AND uid = %d and parent = %d ", intval(local_channel()), intval($r[0]['parent'])); } $o .= '<div id="content-complete"></div>'; return $o; /* elseif((! $update) && (! { $r = q("SELECT `id`, item_flags FROM `item` WHERE `id` = '%s' OR `mid` = '%s' LIMIT 1", dbesc($item_hash), dbesc($item_hash) ); if($r) { if(intval($r[0]['item_deleted'])) { notice( t('Item has been removed.') . EOL ); } else { notice( t('Permission denied.') . EOL ); } } else { notice( t('Item not found.') . EOL ); } } */ }
/** * @brief "Render" a conversation or list of items for HTML display. * * There are two major forms of display: * - Sequential or unthreaded ("New Item View" or search results) * - conversation view * * The $mode parameter decides between the various renderings and also * figures out how to determine page owner and other contextual items * that are based on unique features of the calling module. * * @param App &$a * @param array $items * @param string $mode * @param boolean $update * @param string $page_mode default traditional * @param string $prepared_item * @return string */ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $prepared_item = '') { $content_html = ''; $o = ''; require_once 'bbcode.php'; $ssl_state = local_channel() ? true : false; if (local_channel()) { load_pconfig(local_channel(), ''); } $arr_blocked = null; if (local_channel()) { $str_blocked = get_pconfig(local_channel(), 'system', 'blocked'); } if (!local_channel() && $mode == 'network') { $sys = get_sys_channel(); $id = $sys['channel_id']; $str_blocked = get_pconfig($id, 'system', 'blocked'); } if ($str_blocked) { $arr_blocked = explode(',', $str_blocked); for ($x = 0; $x < count($arr_blocked); $x++) { $arr_blocked[$x] = trim($arr_blocked[$x]); } } $profile_owner = 0; $page_writeable = false; $live_update_div = ''; $preview = $page_mode === 'preview' ? true : false; $previewing = $preview ? ' preview ' : ''; if ($mode === 'network') { $profile_owner = local_channel(); $page_writeable = true; if (!$update) { // The special div is needed for liveUpdate to kick in for this page. // We only launch liveUpdate if you aren't filtering in some incompatible // way and also you aren't writing a comment (discovered in javascript). $live_update_div = '<div id="live-network"></div>' . "\r\n" . "<script> var profile_uid = " . $_SESSION['uid'] . "; var netargs = '" . substr($a->cmd, 8) . '?f=' . (x($_GET, 'cid') ? '&cid=' . $_GET['cid'] : '') . (x($_GET, 'search') ? '&search=' . $_GET['search'] : '') . (x($_GET, 'star') ? '&star=' . $_GET['star'] : '') . (x($_GET, 'order') ? '&order=' . $_GET['order'] : '') . (x($_GET, 'bmark') ? '&bmark=' . $_GET['bmark'] : '') . (x($_GET, 'liked') ? '&liked=' . $_GET['liked'] : '') . (x($_GET, 'conv') ? '&conv=' . $_GET['conv'] : '') . (x($_GET, 'spam') ? '&spam=' . $_GET['spam'] : '') . (x($_GET, 'nets') ? '&nets=' . $_GET['nets'] : '') . (x($_GET, 'cmin') ? '&cmin=' . $_GET['cmin'] : '') . (x($_GET, 'cmax') ? '&cmax=' . $_GET['cmax'] : '') . (x($_GET, 'file') ? '&file=' . $_GET['file'] : '') . (x($_GET, 'uri') ? '&uri=' . $_GET['uri'] : '') . "'; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; } } elseif ($mode === 'channel') { $profile_owner = $a->profile['profile_uid']; $page_writeable = $profile_owner == local_channel(); if (!$update) { $tab = notags(trim($_GET['tab'])); if ($tab === 'posts') { // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, // because browser prefetching might change it on us. We have to deliver it with the page. $live_update_div = '<div id="live-channel"></div>' . "\r\n" . "<script> var profile_uid = " . $a->profile['profile_uid'] . "; var netargs = '?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; } } } elseif ($mode === 'display') { $profile_owner = local_channel(); $page_writeable = false; $live_update_div = '<div id="live-display"></div>' . "\r\n"; } elseif ($mode === 'page') { $profile_owner = $a->profile['uid']; $page_writeable = $profile_owner == local_channel(); $live_update_div = '<div id="live-page"></div>' . "\r\n"; } elseif ($mode === 'search') { $live_update_div = '<div id="live-search"></div>' . "\r\n"; } elseif ($mode === 'photos') { $profile_onwer = $a->profile['profile_uid']; $page_writeable = $profile_owner == local_channel(); $live_update_div = '<div id="live-photos"></div>' . "\r\n"; // for photos we've already formatted the top-level item (the photo) $content_html = $a->data['photo_html']; } $page_dropping = local_channel() && local_channel() == $profile_owner ? true : false; if (!feature_enabled($profile_owner, 'multi_delete')) { $page_dropping = false; } $channel = $a->get_channel(); $observer = $a->get_observer(); if ($update) { $return_url = $_SESSION['return_url']; } else { $return_url = $_SESSION['return_url'] = $a->query_string; } load_contact_links(local_channel()); $cb = array('items' => $items, 'mode' => $mode, 'update' => $update, 'preview' => $preview); call_hooks('conversation_start', $cb); $items = $cb['items']; $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'))); // array with html for each thread (parent+comments) $threads = array(); $threadsid = -1; $page_template = get_markup_template("conversation.tpl"); if ($items) { if ($mode === 'network-new' || $mode === 'search' || $mode === 'community') { // "New Item View" on network page or search page results // - just loop through the items and format them minimally for display //$tpl = get_markup_template('search_item.tpl'); $tpl = 'search_item.tpl'; foreach ($items as $item) { if ($arr_blocked) { $blocked = false; foreach ($arr_blocked as $b) { if ($b && $item['author_xchan'] == $b) { $blocked = true; break; } } if ($blocked) { continue; } } $threadsid++; $comment = ''; $owner_url = ''; $owner_photo = ''; $owner_name = ''; $sparkle = ''; if ($mode === 'search' || $mode === 'community') { if ((activity_match($item['verb'], ACTIVITY_LIKE) || activity_match($item['verb'], ACTIVITY_DISLIKE)) && $item['id'] != $item['parent']) { continue; } $nickname = $item['nickname']; } else { $nickname = $a->user['nickname']; } $profile_name = strlen($item['author-name']) ? $item['author-name'] : $item['name']; if ($item['author-link'] && !$item['author-name']) { $profile_name = $item['author-link']; } $tags = array(); $hashtags = array(); $mentions = array(); $sp = false; $profile_link = best_link_url($item, $sp); if ($sp) { $sparkle = ' sparkle'; } else { $profile_link = zid($profile_link); } $normalised = normalise_link(strlen($item['author-link']) ? $item['author-link'] : $item['url']); $profile_name = $item['author']['xchan_name']; $profile_link = $item['author']['xchan_url']; $profile_avatar = $item['author']['xchan_photo_m']; $location = format_location($item); localize_item($item); if ($mode === 'network-new') { $dropping = true; } else { $dropping = false; } $drop = array('pagedropping' => $page_dropping, 'dropping' => $dropping, 'select' => t('Select'), 'delete' => t('Delete')); $star = false; $isstarred = "unstarred icon-star-empty"; $lock = $item['item_private'] || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid']) ? t('Private Message') : false; $likebuttons = false; $shareable = false; $verified = $item['item_flags'] & ITEM_VERIFIED ? t('Message signature validated') : ''; $forged = $item['sig'] && !($item['item_flags'] & ITEM_VERIFIED) ? t('Message signature incorrect') : ''; $unverified = ''; $tags = array(); $terms = get_terms_oftype($item['term'], array(TERM_HASHTAG, TERM_MENTION, TERM_UNKNOWN)); if (count($terms)) { foreach ($terms as $tag) { $tags[] = format_term_for_display($tag); } } $body = prepare_body($item, true); $tmp_item = array('template' => $tpl, 'toplevel' => 'toplevel_item', 'mode' => $mode, 'id' => $preview ? 'P0' : $item['item_id'], 'linktitle' => sprintf(t('View %s\'s profile @ %s'), $profile_name, $profile_url), 'profile_url' => $profile_link, 'item_photo_menu' => item_photo_menu($item), 'name' => $profile_name, 'sparkle' => $sparkle, 'lock' => $lock, 'thumb' => $profile_avatar, 'title' => $item['title'], 'body' => $body, 'tags' => $tags, 'hashtags' => $hashtags, 'mentions' => $mentions, 'verified' => $verified, 'unverified' => $unverified, 'forged' => $forged, 'txt_cats' => t('Categories:'), 'txt_folders' => t('Filed under:'), 'has_cats' => count($categories) ? 'true' : '', 'has_folders' => count($folders) ? 'true' : '', 'categories' => $categories, 'folders' => $folders, 'text' => strip_tags($body), 'ago' => relative_date($item['created']), 'app' => $item['app'], 'str_app' => sprintf(t(' from %s'), $item['app']), 'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'), 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'), 'editedtime' => $item['edited'] != $item['created'] ? sprintf(t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : '', 'expiretime' => $item['expires'] !== NULL_DATE ? sprintf(t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')) : '', 'location' => $location, 'indent' => '', 'owner_name' => $owner_name, 'owner_url' => $owner_url, 'owner_photo' => $owner_photo, 'plink' => get_plink($item, false), 'edpost' => false, 'isstarred' => $isstarred, 'star' => $star, 'drop' => $drop, 'vote' => $likebuttons, 'like' => '', 'dislike' => '', 'comment' => '', 'conv' => $preview ? '' : array('href' => z_root() . '/display/' . $item['mid'], 'title' => t('View in context')), 'previewing' => $previewing, 'wait' => t('Please wait'), 'thread_level' => 1); $arr = array('item' => $item, 'output' => $tmp_item); call_hooks('display_item', $arr); // $threads[$threadsid]['id'] = $item['item_id']; $threads[] = $arr['output']; } } else { // Normal View // logger('conv: items: ' . print_r($items,true)); require_once 'include/ConversationObject.php'; require_once 'include/ItemObject.php'; $conv = new Conversation($mode, $preview, $prepared_item); // In the display mode we don't have a profile owner. if ($mode === 'display' && $items) { $conv->set_profile_owner($items[0]['uid']); } // get all the topmost parents // this shouldn't be needed, as we should have only them in our array // But for now, this array respects the old style, just in case $threads = array(); foreach ($items as $item) { // Check for any blocked authors if ($arr_blocked) { $blocked = false; foreach ($arr_blocked as $b) { if ($b && $item['author_xchan'] == $b) { $blocked = true; break; } } if ($blocked) { continue; } } // Check all the kids too if ($arr_blocked && $item['children']) { for ($d = 0; $d < count($item['children']); $d++) { foreach ($arr_blocked as $b) { if ($b && $item['children'][$d]['author_xchan'] == $b) { $item['children'][$d]['author_blocked'] = true; } } } } builtin_activity_puller($item, $conv_responses); if (!visible_activity($item)) { continue; } $item['pagedrop'] = $page_dropping; if ($item['id'] == $item['parent']) { $item_object = new Item($item); $conv->add_thread($item_object); if ($page_mode === 'list') { $item_object->set_template('conv_list.tpl'); $item_object->set_display_mode('list'); } } } $threads = $conv->get_template_data($conv_responses); if (!$threads) { logger('[ERROR] conversation : Failed to get template data.', LOGGER_DEBUG); $threads = array(); } } } if ($page_mode === 'traditional' || $page_mode === 'preview') { $page_template = get_markup_template("threaded_conversation.tpl"); } elseif ($update) { $page_template = get_markup_template("convobj.tpl"); } else { $page_template = get_markup_template("conv_frame.tpl"); $threads = null; } // if($page_mode === 'preview') // logger('preview: ' . print_r($threads,true)); // Do not un-comment if smarty3 is in use // logger('page_template: ' . $page_template); // logger('nouveau: ' . print_r($threads,true)); $o .= replace_macros($page_template, array('$baseurl' => $a->get_baseurl($ssl_state), '$photo_item' => $content_html, '$live_update' => $live_update_div, '$remove' => t('remove'), '$mode' => $mode, '$user' => $a->user, '$threads' => $threads, '$wait' => t('Loading...'), '$dropping' => $page_dropping ? t('Delete Selected Items') : False)); return $o; }
function mitem_content(&$a) { $uid = local_channel(); $channel = $a->get_channel(); $observer = $a->get_observer(); $ob_hash = $observer ? $observer['xchan_hash'] : ''; if ($a->is_sys && is_site_admin()) { $sys = get_sys_channel(); $uid = intval($sys['channel_id']); $channel = $sys; $ob_hash = $sys['xchan_hash']; } if (!$uid) { notice(t('Permission denied.') . EOL); return ''; } if (argc() < 2 || !$a->data['menu']) { notice(t('Not found.') . EOL); return ''; } $m = menu_fetch($a->data['menu']['menu_name'], $uid, $ob_hash); $a->data['menu_item'] = $m; $menu_list = menu_list($uid); foreach ($menu_list as $menus) { if ($menus['menu_name'] != $m['menu']['menu_name']) { $menu_names[] = $menus['menu_name']; } } $acl = new AccessList($channel); $lockstate = $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid'] ? 'lock' : 'unlock'; if (argc() == 2) { $r = q("select * from menu_item where mitem_menu_id = %d and mitem_channel_id = %d order by mitem_order asc, mitem_desc asc", intval($a->data['menu']['menu_id']), intval($uid)); if ($_GET['display']) { $display = $_GET['display']; } else { $display = $r ? 'none' : 'block'; } $create = replace_macros(get_markup_template('mitemedit.tpl'), array('$menu_id' => $a->data['menu']['menu_id'], '$permissions' => t('Menu Item Permissions'), '$permdesc' => t("(click to open/close)"), '$aclselect' => populate_acl($acl->get(), false), '$mitem_desc' => array('mitem_desc', t('Link Name'), '', 'Visible name of the link', '*'), '$mitem_link' => array('mitem_link', t('Link or Submenu Target'), '', t('Enter URL of the link or select a menu name to create a submenu'), '*', 'list="menu-names"'), '$usezid' => array('usezid', t('Use magic-auth if available'), true, '', array(t('No'), t('Yes'))), '$newwin' => array('newwin', t('Open link in new window'), false, '', array(t('No'), t('Yes'))), '$mitem_order' => array('mitem_order', t('Order in list'), '0', t('Higher numbers will sink to bottom of listing')), '$submit' => t('Submit and finish'), '$submit_more' => t('Submit and continue'), '$display' => $display, '$lockstate' => $lockstate, '$menu_names' => $menu_names, '$sys' => $a->is_sys)); $o .= replace_macros(get_markup_template('mitemlist.tpl'), array('$title' => t('Menu:'), '$create' => $create, '$nametitle' => t('Link Name'), '$targettitle' => t('Link Target'), '$menuname' => $a->data['menu']['menu_name'], '$menudesc' => $a->data['menu']['menu_desc'], '$edmenu' => t('Edit menu'), '$menu_id' => $a->data['menu']['menu_id'], '$mlist' => $r, '$edit' => t('Edit element'), '$drop' => t('Drop element'), '$new' => t('New element'), '$hintmenu' => t('Edit this menu container'), '$hintnew' => t('Add menu element'), '$hintdrop' => t('Delete this menu item'), '$hintedit' => t('Edit this menu item'))); return $o; } if (argc() > 2) { if (intval(argv(2))) { $m = q("select * from menu_item where mitem_id = %d and mitem_channel_id = %d limit 1", intval(argv(2)), intval($uid)); if (!$m) { notice(t('Menu item not found.') . EOL); goaway(z_root() . '/menu' . ($a->is_sys ? '?f=&sys=1' : '')); } $mitem = $m[0]; $lockstate = $mitem['allow_cid'] || $mitem['allow_gid'] || $mitem['deny_cid'] || $mitem['deny_gid'] ? 'lock' : 'unlock'; if (argc() == 4 && argv(3) == 'drop') { menu_sync_packet($uid, get_observer_hash(), $mitem['mitem_menu_id']); $r = menu_del_item($mitem['mitem_menu_id'], $uid, intval(argv(2))); menu_sync_packet($uid, get_observer_hash(), $mitem['mitem_menu_id']); if ($r) { info(t('Menu item deleted.') . EOL); } else { notice(t('Menu item could not be deleted.') . EOL); } goaway(z_root() . '/mitem/' . $mitem['mitem_menu_id'] . ($a->is_sys ? '?f=&sys=1' : '')); } // edit menu item $o = replace_macros(get_markup_template('mitemedit.tpl'), array('$header' => t('Edit Menu Element'), '$menu_id' => $a->data['menu']['menu_id'], '$permissions' => t('Menu Item Permissions'), '$permdesc' => t("(click to open/close)"), '$aclselect' => populate_acl($mitem, false), '$mitem_id' => intval(argv(2)), '$mitem_desc' => array('mitem_desc', t('Link text'), $mitem['mitem_desc'], '', '*'), '$mitem_link' => array('mitem_link', t('Link or Submenu Target'), $mitem['mitem_link'], 'Enter URL of the link or select a menu name to create a submenu', '*', 'list="menu-names"'), '$usezid' => array('usezid', t('Use magic-auth if available'), $mitem['mitem_flags'] & MENU_ITEM_ZID ? 1 : 0, '', array(t('No'), t('Yes'))), '$newwin' => array('newwin', t('Open link in new window'), $mitem['mitem_flags'] & MENU_ITEM_NEWWIN ? 1 : 0, '', array(t('No'), t('Yes'))), '$mitem_order' => array('mitem_order', t('Order in list'), $mitem['mitem_order'], t('Higher numbers will sink to bottom of listing')), '$submit' => t('Submit'), '$lockstate' => $lockstate, '$menu_names' => $menu_names)); return $o; } } }
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 item_content(&$a) { if (!local_channel() && !remote_channel()) { return; } require_once 'include/security.php'; if (argc() == 3 && argv(1) === 'drop' && intval(argv(2))) { require_once 'include/items.php'; $i = q("select id, uid, author_xchan, owner_xchan, source_xchan, item_restrict from item where id = %d limit 1", intval(argv(2))); if ($i) { $can_delete = false; $local_delete = false; if (local_channel() && local_channel() == $i[0]['uid']) { $local_delete = true; } $sys = get_sys_channel(); if (is_site_admin() && $sys['channel_id'] == $i[0]['uid']) { $can_delete = true; } $ob_hash = get_observer_hash(); if ($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) { $can_delete = true; } if (!($can_delete || $local_delete)) { notice(t('Permission denied.') . EOL); return; } // if this is a different page type or it's just a local delete // but not by the item author or owner, do a simple deletion if ($i[0]['item_restrict'] || $local_delete && !$can_delete) { drop_item($i[0]['id']); } else { // complex deletion that needs to propagate and be performed in phases drop_item($i[0]['id'], true, DROPITEM_PHASE1); tag_deliver($i[0]['uid'], $i[0]['id']); } } } }
/** * @brief Creates navigation menu for webpage, layout, blocks, menu sites. * * @return string */ function design_tools() { $channel = get_app()->get_channel(); $sys = false; if (get_app()->is_sys && is_site_admin()) { require_once 'include/identity.php'; $channel = get_sys_channel(); $sys = true; } $who = $channel['channel_address']; return replace_macros(get_markup_template('design_tools.tpl'), array('$title' => t('Design Tools'), '$who' => $who, '$sys' => $sys, '$blocks' => t('Blocks'), '$menus' => t('Menus'), '$layout' => t('Layouts'), '$pages' => t('Pages'))); }
function check_config(&$a) { $build = get_config('system', 'db_version'); if (!intval($build)) { $build = set_config('system', 'db_version', DB_UPDATE_VERSION); } $saved = get_config('system', 'urlverify'); if (!$saved) { set_config('system', 'urlverify', bin2hex(z_root())); } if ($saved && $saved != bin2hex(z_root())) { // our URL changed. Do something. $oldurl = hex2bin($saved); logger('Baseurl changed!'); $oldhost = substr($oldurl, strpos($oldurl, '//') + 2); $host = substr(z_root(), strpos(z_root(), '//') + 2); $is_ip_addr = preg_match("/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\$/", $host) ? true : false; $was_ip_addr = preg_match("/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\$/", $oldhost) ? true : false; // only change the url to an ip address if it was already an ip and not a dns name if (!$is_ip_addr || $is_ip_addr && $was_ip_addr) { fix_system_urls($oldurl, z_root()); set_config('system', 'urlverify', bin2hex(z_root())); } else { logger('Attempt to change baseurl from a DNS name to an IP address was refused.'); } } // This will actually set the url to the one stored in .htconfig, and ignore what // we're passing - unless we are installing and it has never been set. $a->set_baseurl($a->get_baseurl()); // Make sure each site has a system channel. This is now created on install // so we just need to keep this around a couple of weeks until the hubs that // already exist have one $syschan_exists = get_sys_channel(); if (!$syschan_exists) { create_sys_channel(); } if ($build != DB_UPDATE_VERSION) { $stored = intval($build); if (!$stored) { logger('Critical: check_config unable to determine database schema version'); return; } $current = intval(DB_UPDATE_VERSION); if ($stored < $current && file_exists('install/update.php')) { load_config('database'); // We're reporting a different version than what is currently installed. // Run any existing update scripts to bring the database up to current. require_once 'install/update.php'; // make sure that boot.php and update.php are the same release, we might be // updating right this very second and the correct version of the update.php // file may not be here yet. This can happen on a very busy site. if (DB_UPDATE_VERSION == UPDATE_VERSION) { for ($x = $stored; $x < $current; $x++) { if (function_exists('update_r' . $x)) { // There could be a lot of processes running or about to run. // We want exactly one process to run the update command. // So store the fact that we're taking responsibility // after first checking to see if somebody else already has. // If the update fails or times-out completely you may need to // delete the config entry to try again. if (get_config('database', 'update_r' . $x)) { break; } set_config('database', 'update_r' . $x, '1'); // call the specific update $func = 'update_r' . $x; $retval = $func(); if ($retval) { // Prevent sending hundreds of thousands of emails by creating // a lockfile. $lockfile = 'store/[data]/mailsent'; if (file_exists($lockfile) && filemtime($lockfile) > time() - 86400) { return; } @unlink($lockfile); //send the administrator an e-mail file_put_contents($lockfile, $x); $email_tpl = get_intltext_template("update_fail_eml.tpl"); $email_msg = replace_macros($email_tpl, array('$sitename' => $a->config['system']['sitename'], '$siteurl' => $a->get_baseurl(), '$update' => $x, '$error' => sprintf(t('Update %s failed. See error logs.'), $x))); $subject = email_header_encode(sprintf(t('Update Error at %s'), $a->get_baseurl())); mail($a->config['system']['admin_email'], $subject, $email_msg, 'From: Administrator' . '@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit'); //try the logger logger('CRITICAL: Update Failed: ' . $x); } else { set_config('database', 'update_r' . $x, 'success'); } } } set_config('system', 'db_version', DB_UPDATE_VERSION); } } } /** * * Synchronise plugins: * * $a->config['system']['addon'] contains a comma-separated list of names * of plugins/addons which are used on this system. * Go through the database list of already installed addons, and if we have * an entry, but it isn't in the config list, call the unload procedure * and mark it uninstalled in the database (for now we'll remove it). * Then go through the config list and if we have a plugin that isn't installed, * call the install procedure and add it to the database. * */ $r = q("SELECT * FROM `addon` WHERE `installed` = 1"); if ($r) { $installed = $r; } else { $installed = array(); } $plugins = get_config('system', 'addon'); $plugins_arr = array(); if ($plugins) { $plugins_arr = explode(',', str_replace(' ', '', $plugins)); } $a->plugins = $plugins_arr; $installed_arr = array(); if (count($installed)) { foreach ($installed as $i) { if (!in_array($i['name'], $plugins_arr)) { unload_plugin($i['name']); } else { $installed_arr[] = $i['name']; } } } if (count($plugins_arr)) { foreach ($plugins_arr as $p) { if (!in_array($p, $installed_arr)) { load_plugin($p); } } } load_hooks(); }
function store_doc_file($s) { if (is_dir($s)) { return; } $item = array(); $sys = get_sys_channel(); $item['aid'] = 0; $item['uid'] = $sys['channel_id']; if (strpos($s, '.md')) { $mimetype = 'text/markdown'; } elseif (strpos($s, '.html')) { $mimetype = 'text/html'; } else { $mimetype = 'text/bbcode'; } require_once 'include/html2plain.php'; $item['body'] = html2plain(prepare_text(file_get_contents($s), $mimetype, true)); $item['mimetype'] = 'text/plain'; $item['plink'] = z_root() . '/' . str_replace('doc', 'help', $s); $item['owner_xchan'] = $item['author_xchan'] = $sys['channel_hash']; $item['item_type'] = ITEM_TYPE_DOC; $r = q("select item.* from item left join iconfig on item.id = iconfig.iid \n\t\twhere iconfig.cat = 'system' and iconfig.k = 'docfile' and\n\t\ticonfig.v = '%s' and item_type = %d limit 1", dbesc($s), intval(ITEM_TYPE_DOC)); \Zotlabs\Lib\IConfig::Set($item, 'system', 'docfile', $s); if ($r) { $item['id'] = $r[0]['id']; $item['mid'] = $item['parent_mid'] = $r[0]['mid']; $x = item_store_update($item); } else { $item['mid'] = $item['parent_mid'] = item_message_id(); $x = item_store($item); } return $x; }
function like_content(&$a) { $o = ''; $observer = $a->get_observer(); $interactive = $_REQUEST['interactive']; if ($interactive) { $o .= '<h1>' . t('Like/Dislike') . '</h1>'; $o .= EOL . EOL; if (!$observer) { $_SESSION['return_url'] = $a->query_string; $o .= t('This action is restricted to members.') . EOL; $o .= t('Please <a href="rmagic">login with your RedMatrix ID</a> or <a href="register">register as a new RedMatrix member</a> to continue.') . EOL; return $o; } } $verb = notags(trim($_GET['verb'])); if (!$verb) { $verb = 'like'; } switch ($verb) { case 'like': case 'unlike': $activity = ACTIVITY_LIKE; break; case 'dislike': case 'undislike': $activity = ACTIVITY_DISLIKE; break; case 'agree': case 'unagree': $activity = ACTIVITY_AGREE; break; case 'disagree': case 'undisagree': $activity = ACTIVITY_DISAGREE; break; case 'abstain': case 'unabstain': $activity = ACTIVITY_ABSTAIN; break; case 'attendyes': case 'unattendyes': $activity = ACTIVITY_ATTEND; break; case 'attendno': case 'unattendno': $activity = ACTIVITY_ATTENDNO; break; case 'attendmaybe': case 'unattendmaybe': $activity = ACTIVITY_ATTENDMAYBE; break; default: return; break; } $extended_like = false; $object = $target = null; $post_type = ''; $objtype = ''; if (argc() == 3) { if (!$observer) { killme(); } $extended_like = true; $obj_type = argv(1); $obj_id = argv(2); $public = true; if ($obj_type == 'profile') { $r = q("select * from profile where profile_guid = '%s' limit 1", dbesc(argv(2))); if (!$r) { killme(); } $owner_uid = $r[0]['uid']; if ($r[0]['is_default']) { $public = true; } if (!$public) { $d = q("select abook_xchan from abook where abook_profile = '%s' and abook_channel = %d", dbesc($r[0]['profile_guid']), intval($owner_uid)); if (!$d) { // forgery - illegal if ($interactive) { notice(t('Invalid request.') . EOL); return $o; } killme(); } // $d now contains a list of those who can see this profile - only send the status notification // to them. $allow_cid = $allow_gid = $deny_cid = $deny_gid = ''; foreach ($d as $dd) { $allow_gid .= '<' . $dd['abook_xchan'] . '>'; } } $post_type = t('channel'); $objtype = ACTIVITY_OBJ_PROFILE; } elseif ($obj_type == 'thing') { $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' \n\t\t\t\tand obj_type = %d and term_hash = '%s' limit 1", intval(TERM_OBJ_THING), dbesc(argv(2))); if (!$r) { if ($interactive) { notice(t('Invalid request.') . EOL); return $o; } killme(); } $owner_uid = $r[0]['obj_channel']; $allow_cid = $r[0]['allow_cid']; $allow_gid = $r[0]['allow_gid']; $deny_cid = $r[0]['deny_cid']; $deny_gid = $r[0]['deny_gid']; if ($allow_cid || $allow_gid || $deny_cid || $deny_gid) { $public = false; } $post_type = t('thing'); $objtype = ACTIVITY_OBJ_PROFILE; $tgttype = ACTIVITY_OBJ_THING; $links = array(); $links[] = array('rel' => 'alternate', 'type' => 'text/html', 'href' => z_root() . '/thing/' . $r[0]['term_hash']); if ($r[0]['imgurl']) { $links[] = array('rel' => 'photo', 'href' => $r[0]['imgurl']); } $target = json_encode(array('type' => $tgttype, 'title' => $r[0]['term'], 'id' => z_root() . '/thing/' . $r[0]['term_hash'], 'link' => $links)); $plink = '[zrl=' . z_root() . '/thing/' . $r[0]['term_hash'] . ']' . $r[0]['term'] . '[/zrl]'; } if (!($owner_uid && $r)) { if ($interactive) { notice(t('Invalid request.') . EOL); return $o; } killme(); } // The resultant activity is going to be a wall-to-wall post, so make sure this is allowed $perms = get_all_perms($owner_uid, $observer['xchan_hash']); if (!($perms['post_like'] && $perms['view_profile'])) { if ($interactive) { notice(t('Permission denied.') . EOL); return $o; } killme(); } $ch = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", intval($owner_uid)); if (!$ch) { if ($interactive) { notice(t('Channel unavailable.') . EOL); return $o; } killme(); } if (!$plink) { $plink = '[zrl=' . z_root() . '/profile/' . $ch[0]['channel_address'] . ']' . $post_type . '[/zrl]'; } $links = array(); $links[] = array('rel' => 'alternate', 'type' => 'text/html', 'href' => z_root() . '/profile/' . $ch[0]['channel_address']); $links[] = array('rel' => 'photo', 'type' => $ch[0]['xchan_photo_mimetype'], 'href' => $ch[0]['xchan_photo_l']); $object = json_encode(array('type' => ACTIVITY_OBJ_PROFILE, 'title' => $ch[0]['channel_name'], 'id' => $ch[0]['xchan_url'] . '/' . $ch[0]['xchan_hash'], 'link' => $links)); // second like of the same thing is "undo" for the first like $z = q("select * from likes where channel_id = %d and liker = '%s' and verb = '%s' and target_type = '%s' and target_id = '%s' limit 1", intval($ch[0]['channel_id']), dbesc($observer['xchan_hash']), dbesc($activity), dbesc($tgttype ? $tgttype : $objtype), dbesc($obj_id)); if ($z) { q("delete from likes where id = %d limit 1", intval($z[0]['id'])); drop_item($z[0]['iid'], false); if ($interactive) { notice(t('Previous action reversed.') . EOL); return $o; } killme(); } } else { // this is used to like an item or comment $item_id = argc() == 2 ? notags(trim(argv(1))) : 0; logger('like: verb ' . $verb . ' item ' . $item_id, LOGGER_DEBUG); // get the item. Allow linked photos (which are normally hidden) to be liked $r = q("SELECT * FROM item WHERE id = %d and (item_restrict = 0 or item_restrict = %d) LIMIT 1", intval($item_id), intval(ITEM_HIDDEN)); if (!$item_id || !$r) { logger('like: no item ' . $item_id); killme(); } $item = $r[0]; $owner_uid = $item['uid']; $owner_aid = $item['aid']; $sys = get_sys_channel(); // if this is a "discover" item, (item['uid'] is the sys channel), // fallback to the item comment policy, which should've been // respected when generating the conversation thread. // Even if the activity is rejected by the item owner, it should still get attached // to the local discover conversation on this site. if ($owner_uid != $sys['channel_id'] && !perm_is_allowed($owner_uid, $observer['xchan_hash'], 'post_comments')) { notice(t('Permission denied') . EOL); killme(); } $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($item['owner_xchan'])); if ($r) { $thread_owner = $r[0]; } else { killme(); } $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($item['author_xchan'])); if ($r) { $item_author = $r[0]; } else { killme(); } $verbs = " '" . dbesc($activity) . "' "; $multi_undo = 0; // event participation and consensus items are essentially radio toggles. If you make a subsequent choice, // we need to eradicate your first choice. if ($activity === ACTIVITY_ATTEND || $activity === ACTIVITY_ATTENDNO || $activity === ACTIVITY_ATTENDMAYBE) { $verbs = " '" . dbesc(ACTIVITY_ATTEND) . "','" . dbesc(ACTIVITY_ATTENDNO) . "','" . dbesc(ACTIVITY_ATTENDMAYBE) . "' "; $multi_undo = 1; } if ($activity === ACTIVITY_AGREE || $activity === ACTIVITY_DISAGREE || $activity === ACTIVITY_ABSTAIN) { $verbs = " '" . dbesc(ACTIVITY_AGREE) . "','" . dbesc(ACTIVITY_DISAGREE) . "','" . dbesc(ACTIVITY_ABSTAIN) . "' "; $multi_undo = 1; } $r = q("SELECT id, parent, uid, verb FROM item WHERE verb in ( {$verbs} ) AND item_restrict = 0 \n\t\t\tAND author_xchan = '%s' AND ( parent = %d OR thr_parent = '%s') and uid = %d ", dbesc($observer['xchan_hash']), intval($item_id), dbesc($item['mid']), intval($owner_uid)); if ($r) { // already liked it. Drop that item. require_once 'include/items.php'; foreach ($r as $rr) { drop_item($rr['id'], false, DROPITEM_PHASE1); // set the changed timestamp on the parent so we'll see the update without a page reload $z = q("update item set changed = '%s' where id = %d and uid = %d", dbesc(datetime_convert()), intval($rr['parent']), intval($rr['uid'])); // Prior activity was a duplicate of the one we're submitting, just undo it; // don't fall through and create another if (activity_match($rr['verb'], $activity)) { $multi_undo = false; } } if ($interactive) { return; } if (!$multi_undo) { killme(); } } } $mid = item_message_id(); if ($extended_like) { $item_flags = ITEM_THREAD_TOP | ITEM_ORIGIN | ITEM_WALL; } else { $post_type = $item['resource_type'] === 'photo' ? t('photo') : t('status'); if ($item['obj_type'] === ACTIVITY_OBJ_EVENT) { $post_type = t('event'); } $links = array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item['plink'])); $objtype = $item['resource_type'] === 'photo' ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE; $body = $item['body']; $object = json_encode(array('type' => $objtype, 'id' => $item['mid'], 'parent' => $item['thr_parent'] ? $item['thr_parent'] : $item['parent_mid'], 'link' => $links, 'title' => $item['title'], 'content' => $item['body'], 'created' => $item['created'], 'edited' => $item['edited'], 'author' => array('name' => $item_author['xchan_name'], 'address' => $item_author['xchan_addr'], 'guid' => $item_author['xchan_guid'], 'guid_sig' => $item_author['xchan_guid_sig'], 'link' => array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']), array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m']))))); if (!($item['item_flags'] & ITEM_THREAD_TOP)) { $post_type = 'comment'; } $item_flags = ITEM_ORIGIN | ITEM_NOTSHOWN; if ($item['item_flags'] & ITEM_WALL) { $item_flags |= ITEM_WALL; } // if this was a linked photo and was hidden, unhide it. if ($item['item_restrict'] & ITEM_HIDDEN) { $r = q("update item set item_restrict = (item_restrict ^ %d) where id = %d", intval(ITEM_HIDDEN), intval($item['id'])); } } if ($verb === 'like') { $bodyverb = t('%1$s likes %2$s\'s %3$s'); } if ($verb === 'dislike') { $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s'); } if ($verb === 'agree') { $bodyverb = t('%1$s agrees with %2$s\'s %3$s'); } if ($verb === 'disagree') { $bodyverb = t('%1$s doesn\'t agree with %2$s\'s %3$s'); } if ($verb === 'abstain') { $bodyverb = t('%1$s abstains from a decision on %2$s\'s %3$s'); } if ($verb === 'attendyes') { $bodyverb = t('%1$s is attending %2$s\'s %3$s'); } if ($verb === 'attendno') { $bodyverb = t('%1$s is not attending %2$s\'s %3$s'); } if ($verb === 'attendmaybe') { $bodyverb = t('%1$s may attend %2$s\'s %3$s'); } if (!isset($bodyverb)) { killme(); } $arr = array(); if ($extended_like) { $ulink = '[zrl=' . $ch[0]['xchan_url'] . ']' . $ch[0]['xchan_name'] . '[/zrl]'; $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; $private = $public ? 0 : 1; } else { $arr['parent'] = $item['id']; $arr['thr_parent'] = $item['mid']; $ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]'; $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; $plink = '[zrl=' . $a->get_baseurl() . '/display/' . $item['mid'] . ']' . $post_type . '[/zrl]'; $allow_cid = $item['allow_cid']; $allow_gid = $item['allow_gid']; $deny_cid = $item['deny_cid']; $deny_gid = $item['deny_gid']; $private = $item['private']; } $arr['mid'] = $mid; $arr['aid'] = $extended_like ? $ch[0]['channel_account_id'] : $owner_aid; $arr['uid'] = $owner_uid; $arr['item_flags'] = $item_flags; $arr['parent_mid'] = $extended_like ? $mid : $item['mid']; $arr['owner_xchan'] = $extended_like ? $ch[0]['xchan_hash'] : $thread_owner['xchan_hash']; $arr['author_xchan'] = $observer['xchan_hash']; $arr['body'] = sprintf($bodyverb, $alink, $ulink, $plink); if ($obj_type === 'thing' && $r[0]['imgurl']) { $arr['body'] .= "\n\n[zmg=80x80]" . $r[0]['imgurl'] . '[/zmg]'; } $arr['verb'] = $activity; $arr['obj_type'] = $objtype; $arr['object'] = $object; if ($target) { $arr['tgt_type'] = $tgttype; $arr['target'] = $target; } $arr['allow_cid'] = $allow_cid; $arr['allow_gid'] = $allow_gid; $arr['deny_cid'] = $deny_cid; $arr['deny_gid'] = $deny_gid; $arr['item_private'] = $private; $post = item_store($arr); $post_id = $post['item_id']; $arr['id'] = $post_id; call_hooks('post_local_end', $arr); if ($extended_like) { $r = q("insert into likes (channel_id,liker,likee,iid,verb,target_type,target_id,target) values (%d,'%s','%s',%d,'%s','%s','%s','%s')", intval($ch[0]['channel_id']), dbesc($observer['xchan_hash']), dbesc($ch[0]['channel_hash']), intval($post_id), dbesc($activity), dbesc($tgttype ? $tgttype : $objtype), dbesc($obj_id), dbesc(json_encode($target ? $target : $object))); } proc_run('php', "include/notifier.php", "like", "{$post_id}"); if ($interactive) { notice(t('Action completed.') . EOL); $o .= t('Thank you.'); return $o; } killme(); }
function get_theme_uid() { $uid = $_REQUEST['puid'] ? intval($_REQUEST['puid']) : 0; if (local_channel()) { if (get_pconfig(local_channel(), 'system', 'always_my_theme') || !$uid) { return local_channel(); } } if (!$uid) { $x = get_sys_channel(); if ($x) { return $x['channel_id']; } } return $uid; }
/** * @brief * * A public message with no listed recipients can be delivered to anybody who * has PERMS_NETWORK for that type of post, PERMS_AUTHED (in-network senders are * by definition authenticated) or PERMS_SITE and is one the same site, * or PERMS_SPECIFIC and the sender is a contact who is granted permissions via * their connection permissions in the address book. * Here we take a given message and construct a list of hashes of everybody * on the site that we should try and deliver to. * Some of these will be rejected, but this gives us a place to start. * * @param array $msg * @return NULL|array */ function public_recips($msg) { require_once 'include/identity.php'; $check_mentions = false; $include_sys = false; if ($msg['message']['type'] === 'activity') { if (!get_config('system', 'disable_discover_tab')) { $include_sys = true; } $col = 'channel_w_stream'; $field = PERMS_W_STREAM; if (array_key_exists('flags', $msg['message']) && in_array('thread_parent', $msg['message']['flags'])) { // check mention recipient permissions on top level posts only $check_mentions = true; } else { // This doesn't look like it works so I have to explain what happened. These are my // notes (below) from when I got this section of code working. You would think that // we only have to find those with the requisite stream or comment permissions, // depending on whether this is a top-level post or a comment - but you would be wrong. // ... so public_recips and allowed_public_recips is working so much better // than before, but was still not quite right. We seem to be getting all the right // results for top-level posts now, but comments aren't getting through on channels // for which we've allowed them to send us their stream, but not comment on our posts. // The reason is we were seeing if they could comment - and we only need to do that if // we own the post. If they own the post, we only need to check if they can send us their stream. // if this is a comment and it wasn't sent by the post owner, check to see who is allowing them to comment. // We should have one specific recipient and this step shouldn't be needed unless somebody stuffed up // their software. We may need this step to protect us from bad guys intentionally stuffing up their software. // If it is sent by the post owner, we don't need to do this. We only need to see who is receiving the // owner's stream (which was already set above) - as they control the comment permissions, not us. // Note that by doing this we introduce another bug because some public forums have channel_w_stream // permissions set to themselves only. We also need in this function to add these public forums to the // public recipient list based on if they are tagged or not and have tag permissions. This is complicated // by the fact that this activity doesn't have the public forum tag. It's the parent activity that // contains the tag. we'll solve that further below. if ($msg['notify']['sender']['guid_sig'] != $msg['message']['owner']['guid_sig']) { $col = 'channel_w_comment'; $field = PERMS_W_COMMENT; } } } elseif ($msg['message']['type'] === 'mail') { $col = 'channel_w_mail'; $field = PERMS_W_MAIL; } if (!$col) { return NULL; } $col = dbesc($col); // First find those channels who are accepting posts from anybody, or at least // something greater than just their connections. if ($msg['notify']['sender']['url'] === z_root()) { $sql = " where (( " . $col . " & " . intval(PERMS_NETWORK) . " ) > 0\n\t\t\t\t\tor ( " . $col . " & " . intval(PERMS_SITE) . " ) > 0\n\t\t\t\t\tor ( " . $col . " & " . intval(PERMS_PUBLIC) . ") > 0\n\t\t\t\t\tor ( " . $col . " & " . intval(PERMS_AUTHED) . ") > 0 ) "; } else { $sql = " where ( " . $col . " = " . intval(PERMS_NETWORK) . " \n\t\t\t\t\tor " . $col . " = " . intval(PERMS_PUBLIC) . "\n\t\t\t\t\tor " . $col . " = " . intval(PERMS_AUTHED) . " ) "; } $r = q("select channel_hash as hash from channel {$sql} or channel_hash = '%s'\n\t\tand channel_removed = 0 ", dbesc($msg['notify']['sender']['hash'])); if (!$r) { $r = array(); } // Now we have to get a bit dirty. Find every channel that has the sender in their connections (abook) // and is allowing this sender at least at a high level. $x = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id\n\t\twhere abook_xchan = '%s' and channel_removed = 0\n\t\tand (( " . $col . " = " . intval(PERMS_SPECIFIC) . " and ( abook_my_perms & " . intval($field) . " ) > 0 )\n\t\tOR " . $col . " = " . intval(PERMS_PENDING) . " \n\t\tOR ( " . $col . " = " . intval(PERMS_CONTACTS) . " and abook_pending = 0 )) ", dbesc($msg['notify']['sender']['hash'])); if (!$x) { $x = array(); } $r = array_merge($r, $x); //logger('message: ' . print_r($msg['message'],true)); if ($include_sys && array_key_exists('public_scope', $msg['message']) && $msg['message']['public_scope'] === 'public') { $sys = get_sys_channel(); if ($sys) { $r[] = array('hash' => $sys['channel_hash']); } } // look for any public mentions on this site // They will get filtered by tgroup_check() so we don't need to check permissions now if ($check_mentions) { // It's a top level post. Look at the tags. See if any of them are mentions and are on this hub. if ($msg['message']['tags']) { if (is_array($msg['message']['tags']) && $msg['message']['tags']) { foreach ($msg['message']['tags'] as $tag) { if ($tag['type'] === 'mention' && strpos($tag['url'], z_root()) !== false) { $address = basename($tag['url']); if ($address) { $z = q("select channel_hash as hash from channel where channel_address = '%s' \n\t\t\t\t\t\t\t\tand channel_removed = 0 limit 1", dbesc($address)); if ($z) { $r = array_merge($r, $z); } } } } } } } else { // This is a comment. We need to find any parent with ITEM_UPLINK set. But in fact, let's just return // everybody that stored a copy of the parent. This way we know we're covered. We'll check the // comment permissions when we deliver them. if ($msg['message']['message_top']) { $z = q("select owner_xchan as hash from item where parent_mid = '%s' ", dbesc($msg['message']['message_top'])); if ($z) { $r = array_merge($r, $z); } } } // There are probably a lot of duplicates in $r at this point. We need to filter those out. // It's a bit of work since it's a multi-dimensional array if ($r) { $uniq = array(); foreach ($r as $rr) { if (!in_array($rr['hash'], $uniq)) { $uniq[] = $rr['hash']; } } $r = array(); foreach ($uniq as $rr) { $r[] = array('hash' => $rr); } } logger('public_recips: ' . print_r($r, true), LOGGER_DATA); return $r; }
function drop_item($id, $interactive = true, $stage = DROPITEM_NORMAL, $force = false) { $a = get_app(); // locate item to be deleted $r = q("SELECT * FROM item WHERE id = %d LIMIT 1", intval($id)); if (!$r || $r[0]['item_restrict'] & ITEM_DELETED && $stage === DROPITEM_NORMAL) { if (!$interactive) { return 0; } notice(t('Item not found.') . EOL); goaway($a->get_baseurl() . '/' . $_SESSION['return_url']); } $item = $r[0]; $linked_item = $item['resource_id'] ? true : false; $ok_to_delete = false; // system deletion if (!$interactive) { $ok_to_delete = true; } // owner deletion if (local_channel() && local_channel() == $item['uid']) { $ok_to_delete = true; } // sys owned item, requires site admin to delete $sys = get_sys_channel(); if (is_site_admin() && $sys['channel_id'] == $item['uid']) { $ok_to_delete = true; } // author deletion $observer = $a->get_observer(); if ($observer && $observer['xchan_hash'] && $observer['xchan_hash'] === $item['author_xchan']) { $ok_to_delete = true; } if ($ok_to_delete) { // set the deleted flag immediately on this item just in case the // hook calls a remote process which loops. We'll delete it properly in a second. $r = q("UPDATE item SET item_restrict = ( item_restrict | %d ) WHERE id = %d", intval($linked_item && !$force ? ITEM_HIDDEN : ITEM_DELETED), intval($item['id'])); $arr = array('item' => $item, 'interactive' => $interactive, 'stage' => $stage); call_hooks('drop_item', $arr); $notify_id = intval($item['id']); $items = q("select * from item where parent = %d and uid = %d", intval($item['id']), intval($item['uid'])); if ($items) { foreach ($items as $i) { delete_item_lowlevel($i, $stage, $force); } } else { delete_item_lowlevel($item, $stage, $force); } if (!$interactive) { return 1; } // send the notification upstream/downstream as the case may be // only send notifications to others if this is the owner's wall item. // This isn't optimal. We somehow need to pass to this function whether or not // to call the notifier, or we need to call the notifier from the calling function. // We'll rely on the undocumented behaviour that DROPITEM_PHASE1 is (hopefully) only // set if we know we're going to send delete notifications out to others. if ($item['item_flags'] & ITEM_WALL && $stage != DROPITEM_PHASE2 || $stage == DROPITEM_PHASE1) { proc_run('php', 'include/notifier.php', 'drop', $notify_id); } goaway($a->get_baseurl() . '/' . $_SESSION['return_url']); } else { if (!$interactive) { return 0; } notice(t('Permission denied.') . EOL); goaway($a->get_baseurl() . '/' . $_SESSION['return_url']); } }
function webpages_content(&$a) { 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'); if (!$mimetype) { $mimetype = 'choose'; } $layout = $_REQUEST['layout'] ? $_REQUEST['layout'] : get_pconfig($owner, 'system', 'page_layout'); if (!$layout) { $layout = 'choose'; } // 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', 'bang' => '', 'acl' => $is_owner ? populate_acl($channel_acl, false) : '', 'showacl' => $is_owner ? true : false, 'visitor' => true, 'profile_uid' => intval($owner), 'mimetype' => $mimetype, 'layout' => $layout, '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\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; }
function api_statuses_public_timeline(&$a, $type) { if (api_user() === false) { return false; } $user_info = api_get_user($a); $sys = get_sys_channel(); // params $count = x($_REQUEST, 'count') ? $_REQUEST['count'] : 20; $page = x($_REQUEST, 'page') ? $_REQUEST['page'] - 1 : 0; if ($page < 0) { $page = 0; } $since_id = x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0; $max_id = x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0; //$since_id = 0;//$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0); $start = $page * $count; //$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false); if ($max_id > 0) { $sql_extra = 'AND `item`.`id` <= ' . intval($max_id); } require_once 'include/security.php'; $item_normal = item_normal(); $r = q("select * from item where allow_cid = '' and allow_gid = ''\n\t\t\tand deny_cid = '' and deny_gid = ''\n and item_private = 0\n\t\t\t{$item_normal}\n\t\t\tand uid = " . $sys['channel_id'] . "\n\t\t\t{$sql_extra}\n\t\t\tAND id > %d group by mid\n\t\t\torder by received desc LIMIT %d OFFSET %d ", intval($since_id), intval($count), intval($start)); xchan_query($r, true); $ret = api_format_items($r, $user_info); $data = array('$statuses' => $ret); switch ($type) { case "atom": case "rss": $data = api_rss_extra($a, $data, $user_info); break; case "as": $as = api_format_as($a, $ret, $user_info); $as['title'] = $a->config['sitename'] . " " . t('Public Timeline'); $as['link']['url'] = $a->get_baseurl() . "/"; return $as; break; } return api_apply_template("timeline", $type, $data); }
function public_content(&$a, $update = 0, $load = false) { if ($load) { $_SESSION['loadtime'] = datetime_convert(); } if (get_config('system', 'block_public') && !get_account_id() && !remote_channel()) { return login(); } if (get_config('system', 'disable_discover_tab')) { return; } $item_normal = item_normal(); if (!$update) { $maxheight = get_config('system', 'home_divmore_height'); if (!$maxheight) { $maxheight = 400; } $o .= '<div id="live-public"></div>' . "\r\n"; $o .= "<script> var profile_uid = " . (intval(local_channel()) ? local_channel() : -1) . "; 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' => 'public', '$uid' => local_channel() ? local_channel() : '0', '$gid' => '0', '$cid' => '0', '$cmin' => '0', '$cmax' => '99', '$star' => '0', '$liked' => '0', '$conv' => '0', '$spam' => '0', '$fh' => '1', '$nouveau' => '0', '$wall' => '0', '$list' => '0', '$page' => App::$pager['page'] != 1 ? App::$pager['page'] : 1, '$search' => '', '$order' => 'comment', '$file' => '', '$cats' => '', '$tags' => '', '$dend' => '', '$mid' => '', '$verb' => '', '$dbegin' => '')); } if ($update && !$load) { // only setup pagination on initial page view $pager_sql = ''; } else { App::set_pager_itemspage(20); $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); } require_once 'include/identity.php'; require_once 'include/security.php'; if (get_config('system', 'site_firehose')) { $uids = " and item.uid in ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) and item_private = 0 and item_wall = 1 "; } else { $sys = get_sys_channel(); $uids = " and item.uid = " . intval($sys['channel_id']) . " "; $sql_extra = item_permissions_sql($sys['channel_id']); App::$data['firehose'] = intval($sys['channel_id']); } if (get_config('system', 'public_list_mode')) { $page_mode = 'list'; } else { $page_mode = 'client'; } $simple_update = $update ? " and item.item_unseen = 1 " : ''; 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 = ''; } //logger('update: ' . $update . ' load: ' . $load); if ($update) { $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\tleft join abook on item.author_xchan = abook.abook_xchan\n\t\t\t\tWHERE true {$uids} {$item_normal}\n\t\t\t\tAND item.parent = item.id\n\t\t\t\tand (abook.abook_blocked = 0 or abook.abook_flags is null)\n\t\t\t\t{$sql_extra3} {$sql_extra} {$sql_nets}\n\t\t\t\tORDER BY {$ordering} DESC {$pager_sql} "); } elseif ($update) { $r = q("SELECT distinct item.id AS item_id, {$ordering} FROM item\n\t\t\t\tleft join abook on item.author_xchan = abook.abook_xchan\n\t\t\t\tWHERE true {$uids} {$item_normal}\n\t\t\t\tAND item.parent = item.id {$simple_update}\n\t\t\t\tand (abook.abook_blocked = 0 or abook.abook_flags is null)\n\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\tWHERE true {$uids} {$item_normal}\n\t\t\t\tAND item.parent IN ( %s )\n\t\t\t\t{$sql_extra} ", dbesc($parents_str)); xchan_query($items, true, -1); $items = fetch_post_tags($items, true); $items = conv_sort($items, $ordering); } else { $items = array(); } } // fake it $mode = 'network'; $o .= conversation($a, $items, $mode, $update, $page_mode); if ($items && !$update) { $o .= alt_pager($a, count($items)); } return $o; }