/** * Get data in a form usable by a conversation template * * Returns: * _ The data requested on success * _ false on failure */ public function get_template_data($conv_responses, $thread_level = 1) { $result = array(); $a = $this->get_app(); $item = $this->get_data(); $commentww = ''; $sparkle = ''; $buttons = ''; $dropping = false; $star = false; $isstarred = "unstarred icon-star-empty"; $indent = ''; $osparkle = ''; $total_children = $this->count_descendants(); $unseen_comments = $item['real_uid'] ? 0 : $this->count_unseen_descendants(); $conv = $this->get_conversation(); $observer = $conv->get_observer(); $lock = $item['item_private'] == 1 || $item['uid'] == local_channel() && (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) ? t('Private Message') : false; $shareable = $conv->get_profile_owner() == local_channel() && local_channel() && $item['item_private'] != 1 ? true : false; // allow an exemption for sharing stuff from your private feeds if ($item['author']['xchan_network'] === 'rss') { $shareable = true; } $mode = $conv->get_mode(); if (local_channel() && $observer['xchan_hash'] === $item['author_xchan']) { $edpost = array($a->get_baseurl($ssl_state) . "/editpost/" . $item['id'], t("Edit")); } else { $edpost = false; } if ($observer['xchan_hash'] == $this->get_data_value('author_xchan') || $observer['xchan_hash'] == $this->get_data_value('owner_xchan') || $this->get_data_value('uid') == local_channel()) { $dropping = true; } if (array_key_exists('real_uid', $item)) { $edpost = false; $dropping = false; } if ($dropping) { $drop = array('dropping' => $dropping, 'delete' => t('Delete')); } // FIXME if ($observer_is_pageowner) { $multidrop = array('select' => t('Select')); } $filer = $conv->get_profile_owner() == local_channel() && !array_key_exists('real_uid', $item) ? t("Save to Folder") : false; $profile_avatar = $item['author']['xchan_photo_m']; $profile_link = chanlink_url($item['author']['xchan_url']); $profile_name = $item['author']['xchan_name']; $location = format_location($item); $isevent = false; $attend = null; $canvote = false; // process action responses - e.g. like/dislike/attend/agree/whatever $response_verbs = array('like'); if (feature_enabled($conv->get_profile_owner(), 'dislike')) { $response_verbs[] = 'dislike'; } if ($item['obj_type'] === ACTIVITY_OBJ_EVENT) { $response_verbs[] = 'attendyes'; $response_verbs[] = 'attendno'; $response_verbs[] = 'attendmaybe'; if ($this->is_commentable()) { $isevent = true; $attend = array(t('I will attend'), t('I will not attend'), t('I might attend')); } } $consensus = intval($item['item_consensus']) ? true : false; if ($consensus) { $response_verbs[] = 'agree'; $response_verbs[] = 'disagree'; $response_verbs[] = 'abstain'; if ($this->is_commentable()) { $conlabels = array(t('I agree'), t('I disagree'), t('I abstain')); $canvote = true; } } if (!feature_enabled($conv->get_profile_owner(), 'dislike')) { unset($conv_responses['dislike']); } $responses = get_responses($conv_responses, $response_verbs, $this, $item); $like_count = x($conv_responses['like'], $item['mid']) ? $conv_responses['like'][$item['mid']] : ''; $like_list = x($conv_responses['like'], $item['mid']) ? $conv_responses['like'][$item['mid'] . '-l'] : ''; if (count($like_list) > MAX_LIKERS) { $like_list_part = array_slice($like_list, 0, MAX_LIKERS); array_push($like_list_part, '<a href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>'); } else { $like_list_part = ''; } $like_button_label = tt('Like', 'Likes', $like_count, 'noun'); if (feature_enabled($conv->get_profile_owner(), 'dislike')) { $dislike_count = x($conv_responses['dislike'], $item['mid']) ? $conv_responses['dislike'][$item['mid']] : ''; $dislike_list = x($conv_responses['dislike'], $item['mid']) ? $conv_responses['dislike'][$item['mid'] . '-l'] : ''; $dislike_button_label = tt('Dislike', 'Dislikes', $dislike_count, 'noun'); if (count($dislike_list) > MAX_LIKERS) { $dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS); array_push($dislike_list_part, '<a href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>'); } else { $dislike_list_part = ''; } } $showlike = x($conv_responses['like'], $item['mid']) ? format_like($conv_responses['like'][$item['mid']], $conv_responses['like'][$item['mid'] . '-l'], 'like', $item['mid']) : ''; $showdislike = x($conv_responses['dislike'], $item['mid']) && feature_enabled($conv->get_profile_owner(), 'dislike') ? format_like($conv_responses['dislike'][$item['mid']], $conv_responses['dislike'][$item['mid'] . '-l'], 'dislike', $item['mid']) : ''; /* * We should avoid doing this all the time, but it depends on the conversation mode * And the conv mode may change when we change the conv, or it changes its mode * Maybe we should establish a way to be notified about conversation changes */ $this->check_wall_to_wall(); if ($this->is_toplevel()) { // FIXME check this permission if ($conv->get_profile_owner() == local_channel() && !array_key_exists('real_uid', $item)) { // FIXME we don't need all this stuff, some can be done in the template $star = array('do' => t("Add Star"), 'undo' => t("Remove Star"), 'toggle' => t("Toggle Star Status"), 'classdo' => intval($item['item_starred']) ? "hidden" : "", 'classundo' => intval($item['item_starred']) ? "" : "hidden", 'isstarred' => intval($item['item_starred']) ? "starred icon-star" : "unstarred icon-star-empty", 'starred' => t('starred')); } } else { $indent = 'comment'; } $verified = intval($item['item_verified']) ? t('Message signature validated') : ''; $forged = $item['sig'] && !intval($item['item_verified']) ? t('Message signature incorrect') : ''; $unverified = ''; // (($this->is_wall_to_wall() && (! intval($item['item_verified']))) ? t('Message cannot be verified') : ''); // FIXME - check this permission if ($conv->get_profile_owner() == local_channel()) { $tagger = array('tagit' => t("Add Tag"), 'classtagger' => ""); } $has_bookmarks = false; if (is_array($item['term'])) { foreach ($item['term'] as $t) { if ($t['type'] == TERM_BOOKMARK) { $has_bookmarks = true; } } } $has_event = false; if ($item['obj_type'] === ACTIVITY_OBJ_EVENT && $conv->get_profile_owner() == local_channel()) { $has_event = true; } if ($this->is_commentable()) { $like = array(t("I like this (toggle)"), t("like")); $dislike = array(t("I don't like this (toggle)"), t("dislike")); } if ($shareable) { $share = array(t('Share This'), t('share')); } $dreport = ''; $keep_reports = intval(get_config('system', 'expire_delivery_reports')); if ($keep_reports === 0) { $keep_reports = 30; } if (!get_config('system', 'disable_dreport') && strcmp(datetime_convert('UTC', 'UTC', $item['created']), datetime_convert('UTC', 'UTC', "now - {$keep_reports} days")) > 0) { $dreport = t('Delivery Report'); } if (strcmp(datetime_convert('UTC', 'UTC', $item['created']), datetime_convert('UTC', 'UTC', 'now - 12 hours')) > 0) { $indent .= ' shiny'; } localize_item($item); $body = prepare_body($item, true); // $viewthread (below) is only valid in list mode. If this is a channel page, build the thread viewing link // since we can't depend on llink or plink pointing to the right local location. $owner_address = substr($item['owner']['xchan_addr'], 0, strpos($item['owner']['xchan_addr'], '@')); $viewthread = $item['llink']; if ($conv->get_mode() === 'channel') { $viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . $item['mid']; } $comment_count_txt = sprintf(tt('%d comment', '%d comments', $total_children), $total_children); $list_unseen_txt = $unseen_comments ? sprintf('%d unseen', $unseen_comments) : ''; $children = $this->get_children(); $has_tags = $body['tags'] || $body['categories'] || $body['mentions'] || $body['attachments'] || $body['folders'] ? true : false; $tmp_item = array('template' => $this->get_template(), 'mode' => $mode, 'type' => implode("", array_slice(explode("/", $item['verb']), -1)), 'body' => $body['html'], 'tags' => $body['tags'], 'categories' => $body['categories'], 'mentions' => $body['mentions'], 'attachments' => $body['attachments'], 'folders' => $body['folders'], 'text' => strip_tags($body['html']), 'id' => $this->get_id(), 'mid' => $item['mid'], 'isevent' => $isevent, 'attend' => $attend, 'consensus' => $consensus, 'conlabels' => $conlabels, 'canvote' => $canvote, 'linktitle' => sprintf(t('View %s\'s profile - %s'), $profile_name, $item['author']['xchan_addr']), 'olinktitle' => sprintf(t('View %s\'s profile - %s'), $this->get_owner_name(), $item['owner']['xchan_addr']), 'llink' => $item['llink'], 'viewthread' => $viewthread, 'to' => t('to'), 'via' => t('via'), 'wall' => t('Wall-to-Wall'), 'vwall' => t('via Wall-To-Wall:'), 'profile_url' => $profile_link, 'item_photo_menu' => item_photo_menu($item), 'dreport' => $dreport, 'name' => $profile_name, 'thumb' => $profile_avatar, 'osparkle' => $osparkle, 'sparkle' => $sparkle, 'title' => $item['title'], 'title_tosource' => get_pconfig($conv->get_profile_owner(), 'system', 'title_tosource'), 'ago' => relative_date($item['created']), 'app' => $item['app'], 'str_app' => sprintf(t('from %s'), $item['app']), 'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'), 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'), 'editedtime' => $item['edited'] != $item['created'] ? sprintf(t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : '', 'expiretime' => $item['expires'] !== NULL_DATE ? sprintf(t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')) : '', 'lock' => $lock, 'verified' => $verified, 'unverified' => $unverified, 'forged' => $forged, 'location' => $location, 'indent' => $indent, 'owner_url' => $this->get_owner_url(), 'owner_photo' => $this->get_owner_photo(), 'owner_name' => $this->get_owner_name(), 'photo' => $body['photo'], 'event' => $body['event'], 'has_tags' => $has_tags, 'like' => $like, 'dislike' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike : '', 'share' => $share, 'rawmid' => $item['mid'], 'plink' => get_plink($item), 'edpost' => $edpost, 'star' => feature_enabled($conv->get_profile_owner(), 'star_posts') ? $star : '', 'tagger' => feature_enabled($conv->get_profile_owner(), 'commtag') ? $tagger : '', 'filer' => feature_enabled($conv->get_profile_owner(), 'filing') ? $filer : '', 'bookmark' => $conv->get_profile_owner() == local_channel() && local_channel() && $has_bookmarks ? t('Save Bookmarks') : '', 'addtocal' => $has_event ? t('Add to Calendar') : '', 'drop' => $drop, 'multidrop' => feature_enabled($conv->get_profile_owner(), 'multi_delete') ? $multidrop : '', 'unseen_comments' => $unseen_comments, 'comment_count' => $total_children, 'comment_count_txt' => $comment_count_txt, 'list_unseen_txt' => $list_unseen_txt, 'markseen' => t('Mark all seen'), 'responses' => $responses, 'like_count' => $like_count, 'like_list' => $like_list, 'like_list_part' => $like_list_part, 'like_button_label' => $like_button_label, 'like_modal_title' => t('Likes', 'noun'), 'dislike_modal_title' => t('Dislikes', 'noun'), 'dislike_count' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_count : '', 'dislike_list' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_list : '', 'dislike_list_part' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_list_part : '', 'dislike_button_label' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_button_label : '', 'modal_dismiss' => t('Close'), 'showlike' => $showlike, 'showdislike' => $showdislike, 'comment' => $this->get_comment_box($indent), 'previewing' => $conv->is_preview() ? ' preview ' : '', 'wait' => t('Please wait'), 'thread_level' => $thread_level); $arr = array('item' => $item, 'output' => $tmp_item); call_hooks('display_item', $arr); $result = $arr['output']; $result['children'] = array(); $nb_children = count($children); $visible_comments = get_config('system', 'expanded_comments'); if ($visible_comments === false) { $visible_comments = 3; } if ($this->get_display_mode() === 'normal' && $nb_children > 0) { foreach ($children as $child) { $result['children'][] = $child->get_template_data($conv_responses, $thread_level + 1); } // Collapse if ($nb_children > $visible_comments || $thread_level > 1) { $result['children'][0]['comment_firstcollapsed'] = true; $result['children'][0]['num_comments'] = $comment_count_txt; $result['children'][0]['hide_text'] = t('[+] show all'); if ($thread_level > 1) { $result['children'][$nb_children - 1]['comment_lastcollapsed'] = true; } else { $result['children'][$nb_children - ($visible_comments + 1)]['comment_lastcollapsed'] = true; } } } $result['private'] = $item['item_private']; $result['toplevel'] = $this->is_toplevel() ? 'toplevel_item' : ''; if ($this->is_threaded()) { $result['flatten'] = false; $result['threaded'] = true; } else { $result['flatten'] = true; $result['threaded'] = false; } return $result; }
function conversation(&$a, $items, $mode, $update, $preview = false) { require_once 'bbcode.php'; $ssl_state = local_user() ? true : false; $profile_owner = 0; $page_writeable = false; $previewing = $preview ? ' preview ' : ''; if ($mode === 'network') { $profile_owner = local_user(); $page_writeable = true; } if ($mode === 'profile') { $profile_owner = $a->profile['profile_uid']; $page_writeable = can_write_wall($a, $profile_owner); } if ($mode === 'notes') { $profile_owner = local_user(); $page_writeable = true; } if ($mode === 'display') { $profile_owner = $a->profile['uid']; $page_writeable = can_write_wall($a, $profile_owner); } if ($mode === 'community') { $profile_owner = 0; $page_writeable = false; } if ($update) { $return_url = $_SESSION['return_url']; } else { $return_url = $_SESSION['return_url'] = $a->query_string; } load_contact_links(local_user()); $cb = array('items' => $items, 'mode' => $mode, 'update' => $update, 'preview' => $preview); call_hooks('conversation_start', $cb); $items = $cb['items']; $cmnt_tpl = get_markup_template('comment_item.tpl'); $tpl = 'wall_item.tpl'; $wallwall = 'wallwall_item.tpl'; $hide_comments_tpl = get_markup_template('hide_comments.tpl'); $alike = array(); $dlike = array(); // array with html for each thread (parent+comments) $threads = array(); $threadsid = -1; if ($items && count($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) { $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']; } // prevent private email from leaking. if ($item['network'] === NETWORK_MAIL && local_user() != $item['uid']) { continue; } $profile_name = strlen($item['author-name']) ? $item['author-name'] : $item['name']; if ($item['author-link'] && !$item['author-name']) { $profile_name = $item['author-link']; } $sp = false; $profile_link = best_link_url($item, $sp); if ($profile_link === 'mailbox') { $profile_link = ''; } if ($sp) { $sparkle = ' sparkle'; } else { $profile_link = zrl($profile_link); } $normalised = normalise_link(strlen($item['author-link']) ? $item['author-link'] : $item['url']); if ($normalised != 'mailbox' && x($a->contacts[$normalised])) { $profile_avatar = $a->contacts[$normalised]['thumb']; } else { $profile_avatar = strlen($item['author-avatar']) ? $item['author-avatar'] : $item['thumb']; } $locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => ''); call_hooks('render_location', $locate); $location = strlen($locate['html']) ? $locate['html'] : render_location_google($locate); localize_item($item); if ($mode === 'network-new') { $dropping = true; } else { $dropping = false; } $drop = array('dropping' => $dropping, 'select' => t('Select'), 'delete' => t('Delete')); $star = false; $isstarred = "unstarred"; $lock = false; $likebuttons = false; $shareable = false; $body = prepare_body($item, true); //$tmp_item = replace_macros($tpl,array( $tmp_item = array('template' => $tpl, 'id' => $preview ? 'P0' : $item['item_id'], 'linktitle' => sprintf(t('View %s\'s profile @ %s'), $profile_name, strlen($item['author-link']) ? $item['author-link'] : $item['url']), 'profile_url' => $profile_link, 'item_photo_menu' => item_photo_menu($item), 'name' => template_escape($profile_name), 'sparkle' => $sparkle, 'lock' => $lock, 'thumb' => $profile_avatar, 'title' => template_escape($item['title']), 'body' => template_escape($body), 'text' => strip_tags(template_escape($body)), 'ago' => $item['app'] ? sprintf(t('%s from %s'), relative_date($item['created']), $item['app']) : relative_date($item['created']), 'location' => template_escape($location), 'indent' => '', 'owner_name' => template_escape($owner_name), 'owner_url' => $owner_url, 'owner_photo' => $owner_photo, 'plink' => get_plink($item), 'edpost' => false, 'isstarred' => $isstarred, 'star' => $star, 'drop' => $drop, 'vote' => $likebuttons, 'like' => '', 'dislike' => '', 'comment' => '', 'conv' => $preview ? '' : array('href' => $a->get_baseurl($ssl_state) . '/display/' . $nickname . '/' . $item['id'], 'title' => t('View in context')), 'previewing' => $previewing, 'wait' => t('Please wait')); $arr = array('item' => $item, 'output' => $tmp_item); call_hooks('display_item', $arr); $threads[$threadsid]['id'] = $item['item_id']; $threads[$threadsid]['items'] = array($arr['output']); } } else { // Normal View // Figure out how many comments each parent has // (Comments all have gravity of 6) // Store the result in the $comments array $comments = array(); foreach ($items as $item) { if (intval($item['gravity']) == 6 && $item['id'] != $item['parent']) { if (!x($comments, $item['parent'])) { $comments[$item['parent']] = 1; } else { $comments[$item['parent']] += 1; } } elseif (!x($comments, $item['parent'])) { $comments[$item['parent']] = 0; } // avoid notices later on } // map all the like/dislike activities for each parent item // Store these in the $alike and $dlike arrays foreach ($items as $item) { like_puller($a, $item, $alike, 'like'); like_puller($a, $item, $dlike, 'dislike'); } $comments_collapsed = false; $comments_seen = 0; $comment_lastcollapsed = false; $comment_firstcollapsed = false; $blowhard = 0; $blowhard_count = 0; foreach ($items as $item) { $comment = ''; $template = $tpl; $commentww = ''; $sparkle = ''; $owner_url = $owner_photo = $owner_name = ''; // We've already parsed out like/dislike for special treatment. We can ignore them now if ((activity_match($item['verb'], ACTIVITY_LIKE) || activity_match($item['verb'], ACTIVITY_DISLIKE)) && $item['id'] != $item['parent']) { continue; } $toplevelpost = $item['id'] == $item['parent'] ? true : false; $toplevelprivate = false; // Take care of author collapsing and comment collapsing // (author collapsing is currently disabled) // If a single author has more than 3 consecutive top-level posts, squash the remaining ones. // If there are more than two comments, squash all but the last 2. if ($toplevelpost) { $toplevelprivate = $toplevelpost && $item['private'] ? true : false; $item_writeable = $item['writable'] || $item['self'] ? true : false; $comments_seen = 0; $comments_collapsed = false; $comment_lastcollapsed = false; $comment_firstcollapsed = false; $threadsid++; $threads[$threadsid]['id'] = $item['item_id']; $threads[$threadsid]['private'] = $item['private']; $threads[$threadsid]['items'] = array(); } else { // prevent private email reply to public conversation from leaking. if ($item['network'] === NETWORK_MAIL && local_user() != $item['uid']) { continue; } $comments_seen++; $comment_lastcollapsed = false; $comment_firstcollapsed = false; } $override_comment_box = $page_writeable && $item_writeable ? true : false; $show_comment_box = $page_writeable && $item_writeable && $comments_seen == $comments[$item['parent']] ? true : false; if ($comments[$item['parent']] > 2 && $comments_seen <= $comments[$item['parent']] - 2 && $item['gravity'] == 6) { if (!$comments_collapsed) { $threads[$threadsid]['num_comments'] = sprintf(tt('%d comment', '%d comments', $comments[$item['parent']]), $comments[$item['parent']]); $threads[$threadsid]['hide_text'] = t('show more'); $comments_collapsed = true; $comment_firstcollapsed = true; } } if ($comments[$item['parent']] > 2 && $comments_seen == $comments[$item['parent']] - 1) { $comment_lastcollapsed = true; } $redirect_url = $a->get_baseurl($ssl_state) . '/redir/' . $item['cid']; $lock = $item['private'] || $item['uid'] == local_user() && (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) ? t('Private Message') : false; // Top-level wall post not written by the wall owner (wall-to-wall) // First figure out who owns it. $osparkle = ''; if ($toplevelpost && !$item['self'] && $mode !== 'profile') { if ($item['wall']) { // On the network page, I am the owner. On the display page it will be the profile owner. // This will have been stored in $a->page_contact by our calling page. // Put this person as the wall owner of the wall-to-wall notice. $owner_url = zrl($a->page_contact['url']); $owner_photo = $a->page_contact['thumb']; $owner_name = $a->page_contact['name']; $template = $wallwall; $commentww = 'ww'; } if (!$item['wall'] && $item['owner-link']) { $owner_linkmatch = $item['owner-link'] && link_compare($item['owner-link'], $item['author-link']); $alias_linkmatch = $item['alias'] && link_compare($item['alias'], $item['author-link']); $owner_namematch = $item['owner-name'] && $item['owner-name'] == $item['author-name']; if (!$owner_linkmatch && !$alias_linkmatch && !$owner_namematch) { // The author url doesn't match the owner (typically the contact) // and also doesn't match the contact alias. // The name match is a hack to catch several weird cases where URLs are // all over the park. It can be tricked, but this prevents you from // seeing "Bob Smith to Bob Smith via Wall-to-wall" and you know darn // well that it's the same Bob Smith. // But it could be somebody else with the same name. It just isn't highly likely. $owner_url = $item['owner-link']; $owner_photo = $item['owner-avatar']; $owner_name = $item['owner-name']; $template = $wallwall; $commentww = 'ww'; // If it is our contact, use a friendly redirect link if (link_compare($item['owner-link'], $item['url']) && $item['network'] === NETWORK_DFRN) { $owner_url = $redirect_url; $osparkle = ' sparkle'; } else { $owner_url = zrl($owner_url); } } } } $likebuttons = ''; $shareable = $profile_owner == local_user() && !$item['private'] ? true : false; //($mode != 'display') && if ($page_writeable) { if ($toplevelpost) { $likebuttons = array('like' => array(t("I like this (toggle)"), t("like")), 'dislike' => array(t("I don't like this (toggle)"), t("dislike"))); if ($shareable) { $likebuttons['share'] = array(t('Share this'), t('share')); } } $qc = $qcomment = null; if (in_array('qcomment', $a->plugins)) { $qc = local_user() ? get_pconfig(local_user(), 'qcomment', 'words') : null; $qcomment = $qc ? explode("\n", $qc) : null; } if ($show_comment_box || $show_comment_box == false && $override_comment_box == false && $item['last-child']) { $comment = replace_macros($cmnt_tpl, array('$return_path' => '', '$jsreload' => $mode === 'display' ? $_SESSION['return_url'] : '', '$type' => $mode === 'profile' ? 'wall-comment' : 'net-comment', '$id' => $item['item_id'], '$parent' => $item['parent'], '$qcomment' => $qcomment, '$profile_uid' => $profile_owner, '$mylink' => $a->contact['url'], '$mytitle' => t('This is you'), '$myphoto' => $a->contact['thumb'], '$comment' => t('Comment'), '$submit' => t('Submit'), '$edbold' => t('Bold'), '$editalic' => t('Italic'), '$eduline' => t('Underline'), '$edquote' => t('Quote'), '$edcode' => t('Code'), '$edimg' => t('Image'), '$edurl' => t('Link'), '$edvideo' => t('Video'), '$preview' => t('Preview'), '$ww' => $mode === 'network' ? $commentww : '')); } } if (local_user() && link_compare($a->contact['url'], $item['author-link'])) { $edpost = array($a->get_baseurl($ssl_state) . "/editpost/" . $item['id'], t("Edit")); } else { $edpost = false; } $drop = ''; $dropping = false; if (intval($item['contact-id']) && $item['contact-id'] == remote_user() || $item['uid'] == local_user()) { $dropping = true; } $drop = array('dropping' => $dropping, 'select' => t('Select'), 'delete' => t('Delete')); $star = false; $filer = false; $isstarred = "unstarred"; if ($profile_owner == local_user()) { if ($toplevelpost) { $isstarred = $item['starred'] ? "starred" : "unstarred"; $star = array('do' => t("add star"), 'undo' => t("remove star"), 'toggle' => t("toggle star status"), 'classdo' => $item['starred'] ? "hidden" : "", 'classundo' => $item['starred'] ? "" : "hidden", 'starred' => t('starred'), 'tagger' => t("add tag"), 'classtagger' => ""); } $filer = t("save to folder"); } $photo = $item['photo']; $thumb = $item['thumb']; // Post was remotely authored. $diff_author = link_compare($item['url'], $item['author-link']) ? false : true; $profile_name = strlen($item['author-name']) && $diff_author ? $item['author-name'] : $item['name']; if ($item['author-link'] && !$item['author-name']) { $profile_name = $item['author-link']; } $sp = false; $profile_link = best_link_url($item, $sp); if ($profile_link === 'mailbox') { $profile_link = ''; } if ($sp) { $sparkle = ' sparkle'; } else { $profile_link = zrl($profile_link); } $normalised = normalise_link(strlen($item['author-link']) ? $item['author-link'] : $item['url']); if ($normalised != 'mailbox' && x($a->contacts, $normalised)) { $profile_avatar = $a->contacts[$normalised]['thumb']; } else { $profile_avatar = strlen($item['author-avatar']) && $diff_author ? $item['author-avatar'] : $thumb; } $like = x($alike, $item['id']) ? format_like($alike[$item['id']], $alike[$item['id'] . '-l'], 'like', $item['id']) : ''; $dislike = x($dlike, $item['id']) ? format_like($dlike[$item['id']], $dlike[$item['id'] . '-l'], 'dislike', $item['id']) : ''; $locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => ''); call_hooks('render_location', $locate); $location = strlen($locate['html']) ? $locate['html'] : render_location_google($locate); $indent = $toplevelpost ? '' : ' comment'; if (strcmp(datetime_convert('UTC', 'UTC', $item['created']), datetime_convert('UTC', 'UTC', 'now - 12 hours')) > 0) { $indent .= ' shiny'; } // localize_item($item); $tags = array(); foreach (explode(',', $item['tag']) as $tag) { $tag = trim($tag); if ($tag != "") { $tags[] = bbcode($tag); } } // Build the HTML $body = prepare_body($item, true); //$tmp_item = replace_macros($template, $tmp_item = array('comment_firstcollapsed' => $comment_firstcollapsed, 'comment_lastcollapsed' => $comment_lastcollapsed, 'template' => $template, 'type' => implode("", array_slice(explode("/", $item['verb']), -1)), 'tags' => $tags, 'body' => template_escape($body), 'text' => strip_tags(template_escape($body)), 'id' => $item['item_id'], 'linktitle' => sprintf(t('View %s\'s profile @ %s'), $profile_name, strlen($item['author-link']) ? $item['author-link'] : $item['url']), 'olinktitle' => sprintf(t('View %s\'s profile @ %s'), $profile_name, strlen($item['owner-link']) ? $item['owner-link'] : $item['url']), 'to' => t('to'), 'wall' => t('Wall-to-Wall'), 'vwall' => t('via Wall-To-Wall:'), 'profile_url' => $profile_link, 'item_photo_menu' => item_photo_menu($item), 'name' => template_escape($profile_name), 'thumb' => $profile_avatar, 'osparkle' => $osparkle, 'sparkle' => $sparkle, 'title' => template_escape($item['title']), 'ago' => $item['app'] ? sprintf(t('%s from %s'), relative_date($item['created']), $item['app']) : relative_date($item['created']), 'lock' => $lock, 'location' => template_escape($location), 'indent' => $indent, 'owner_url' => $owner_url, 'owner_photo' => $owner_photo, 'owner_name' => template_escape($owner_name), 'plink' => get_plink($item), 'edpost' => $edpost, 'isstarred' => $isstarred, 'star' => $star, 'filer' => $filer, 'drop' => $drop, 'vote' => $likebuttons, 'like' => $like, 'dislike' => $dislike, 'comment' => $comment, 'previewing' => $previewing, 'wait' => t('Please wait')); $arr = array('item' => $item, 'output' => $tmp_item); call_hooks('display_item', $arr); $threads[$threadsid]['items'][] = $arr['output']; } } } $page_template = get_markup_template("conversation.tpl"); $o = replace_macros($page_template, array('$baseurl' => $a->get_baseurl($ssl_state), '$mode' => $mode, '$user' => $a->user, '$threads' => $threads, '$dropping' => $dropping ? t('Delete Selected Items') : False)); return $o; }
function conversation(&$a, $items, $mode, $update, $preview = false) { require_once 'include/bbcode.php'; require_once 'mod/proxy.php'; $ssl_state = local_user() ? true : false; $profile_owner = 0; $page_writeable = false; $live_update_div = ''; $arr_blocked = null; if (local_user()) { $str_blocked = get_pconfig(local_user(), 'system', 'blocked'); if ($str_blocked) { $arr_blocked = explode(',', $str_blocked); for ($x = 0; $x < count($arr_blocked); $x++) { $arr_blocked[$x] = trim($arr_blocked[$x]); } } } $previewing = $preview ? ' preview ' : ''; if ($mode === 'network') { $profile_owner = local_user(); $page_writeable = true; if (!$update) { // The special div is needed for liveUpdate to kick in for this page. // We only launch liveUpdate if you aren't filtering in some incompatible // way and also you aren't writing a comment (discovered in javascript). $live_update_div = '<div id="live-network"></div>' . "\r\n" . "<script> var profile_uid = " . $_SESSION['uid'] . "; var netargs = '" . substr($a->cmd, 8) . '?f=' . (x($_GET, 'cid') ? '&cid=' . $_GET['cid'] : '') . (x($_GET, 'search') ? '&search=' . $_GET['search'] : '') . (x($_GET, 'star') ? '&star=' . $_GET['star'] : '') . (x($_GET, 'order') ? '&order=' . $_GET['order'] : '') . (x($_GET, 'bmark') ? '&bmark=' . $_GET['bmark'] : '') . (x($_GET, 'liked') ? '&liked=' . $_GET['liked'] : '') . (x($_GET, 'conv') ? '&conv=' . $_GET['conv'] : '') . (x($_GET, 'spam') ? '&spam=' . $_GET['spam'] : '') . (x($_GET, 'nets') ? '&nets=' . $_GET['nets'] : '') . (x($_GET, 'cmin') ? '&cmin=' . $_GET['cmin'] : '') . (x($_GET, 'cmax') ? '&cmax=' . $_GET['cmax'] : '') . (x($_GET, 'file') ? '&file=' . $_GET['file'] : '') . "'; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; } } else { if ($mode === 'profile') { $profile_owner = $a->profile['profile_uid']; $page_writeable = can_write_wall($a, $profile_owner); if (!$update) { $tab = notags(trim($_GET['tab'])); $tab = $tab ? $tab : 'posts'; 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-profile"></div>' . "\r\n" . "<script> var profile_uid = " . $a->profile['profile_uid'] . "; var netargs = '?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; } } } else { if ($mode === 'notes') { $profile_owner = local_user(); $page_writeable = true; if (!$update) { $live_update_div = '<div id="live-notes"></div>' . "\r\n" . "<script> var profile_uid = " . local_user() . "; var netargs = '/?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; } } else { if ($mode === 'display') { $profile_owner = $a->profile['uid']; $page_writeable = can_write_wall($a, $profile_owner); if (!$update) { $live_update_div = '<div id="live-display"></div>' . "\r\n" . "<script> var profile_uid = " . $_SESSION['uid'] . ";" . " var profile_page = 1; </script>"; } } else { if ($mode === 'community') { $profile_owner = 0; $page_writeable = false; if (!$update) { $live_update_div = '<div id="live-community"></div>' . "\r\n" . "<script> var profile_uid = -1; var netargs = '/?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; } } else { if ($mode === 'search') { $live_update_div = '<div id="live-search"></div>' . "\r\n"; } } } } } } $page_dropping = local_user() && local_user() == $profile_owner ? true : false; if ($update) { $return_url = $_SESSION['return_url']; } else { $return_url = $_SESSION['return_url'] = $a->query_string; } load_contact_links(local_user()); $cb = array('items' => $items, 'mode' => $mode, 'update' => $update, 'preview' => $preview); call_hooks('conversation_start', $cb); $items = $cb['items']; $cmnt_tpl = get_markup_template('comment_item.tpl'); $hide_comments_tpl = get_markup_template('hide_comments.tpl'); $alike = array(); $dlike = array(); // array with html for each thread (parent+comments) $threads = array(); $threadsid = -1; $page_template = get_markup_template("conversation.tpl"); if ($items && count($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 && link_compare($item['author-link'], $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']; } // prevent private email from leaking. if ($item['network'] === NETWORK_MAIL && local_user() != $item['uid']) { continue; } $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(); $taglist = q("SELECT `type`, `term`, `url` FROM `term` WHERE `otype` = %d AND `oid` = %d AND `type` IN (%d, %d) ORDER BY `tid`", intval(TERM_OBJ_POST), intval($item['id']), intval(TERM_HASHTAG), intval(TERM_MENTION)); foreach ($taglist as $tag) { if ($tag["url"] == "") { $tag["url"] = $searchpath . strtolower($tag["term"]); } if ($tag["type"] == TERM_HASHTAG) { $hashtags[] = "#<a href=\"" . $tag["url"] . "\" target=\"_blank\">" . $tag["term"] . "</a>"; $prefix = "#"; } elseif ($tag["type"] == TERM_MENTION) { $mentions[] = "@<a href=\"" . $tag["url"] . "\" target=\"_blank\">" . $tag["term"] . "</a>"; $prefix = "@"; } $tags[] = $prefix . "<a href=\"" . $tag["url"] . "\" target=\"_blank\">" . $tag["term"] . "</a>"; } /*foreach(explode(',',$item['tag']) as $tag){ $tag = trim($tag); if ($tag!="") { $t = bbcode($tag); $tags[] = $t; if($t[0] == '#') $hashtags[] = $t; elseif($t[0] == '@') $mentions[] = $t; } }*/ $sp = false; $profile_link = best_link_url($item, $sp); if ($profile_link === 'mailbox') { $profile_link = ''; } if ($sp) { $sparkle = ' sparkle'; } else { $profile_link = zrl($profile_link); } $normalised = normalise_link(strlen($item['author-link']) ? $item['author-link'] : $item['url']); if ($normalised != 'mailbox' && x($a->contacts[$normalised])) { $profile_avatar = $a->contacts[$normalised]['thumb']; } else { $profile_avatar = strlen($item['author-avatar']) ? $a->get_cached_avatar_image($item['author-avatar']) : $item['thumb']; } $locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => ''); call_hooks('render_location', $locate); $location = strlen($locate['html']) ? $locate['html'] : render_location_google($locate); localize_item($item); if ($mode === 'network-new') { $dropping = true; } else { $dropping = false; } $drop = array('dropping' => $dropping, 'pagedrop' => $page_dropping, 'select' => t('Select'), 'delete' => t('Delete')); $star = false; $isstarred = "unstarred"; $lock = false; $likebuttons = false; $shareable = false; $body = prepare_body($item, true, $preview); list($categories, $folders) = get_cats_and_terms($item); if ($a->theme['template_engine'] === 'internal') { $profile_name_e = template_escape($profile_name); $item['title_e'] = template_escape($item['title']); $body_e = template_escape($body); $tags_e = template_escape($tags); $hashtags_e = template_escape($hashtags); $mentions_e = template_escape($mentions); $location_e = template_escape($location); $owner_name_e = template_escape($owner_name); } else { $profile_name_e = $profile_name; $item['title_e'] = $item['title']; $body_e = $body; $tags_e = $tags; $hashtags_e = $hashtags; $mentions_e = $mentions; $location_e = $location; $owner_name_e = $owner_name; } $tmp_item = array('template' => $tpl, 'id' => $preview ? 'P0' : $item['item_id'], 'network' => $item['item_network'], 'linktitle' => sprintf(t('View %s\'s profile @ %s'), $profile_name, strlen($item['author-link']) ? $item['author-link'] : $item['url']), 'profile_url' => $profile_link, 'item_photo_menu' => item_photo_menu($item), 'name' => $profile_name_e, 'sparkle' => $sparkle, 'lock' => $lock, 'thumb' => proxy_url($profile_avatar), 'title' => $item['title_e'], 'body' => $body_e, 'tags' => $tags_e, 'hashtags' => $hashtags_e, 'mentions' => $mentions_e, '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_e), 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'), 'ago' => $item['app'] ? sprintf(t('%s from %s'), relative_date($item['created']), $item['app']) : relative_date($item['created']), 'location' => $location_e, 'indent' => '', 'owner_name' => $owner_name_e, 'owner_url' => $owner_url, 'owner_photo' => proxy_url($owner_photo), 'plink' => get_plink($item), 'edpost' => false, 'isstarred' => $isstarred, 'star' => $star, 'drop' => $drop, 'vote' => $likebuttons, 'like' => '', 'dislike' => '', 'comment' => '', 'conv' => $preview ? '' : array('href' => $a->get_baseurl($ssl_state) . '/display/' . $item['guid'], '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[$threadsid]['network'] = $item['item_network']; $threads[$threadsid]['items'] = array($arr['output']); } } else { // Normal View $page_template = get_markup_template("threaded_conversation.tpl"); require_once 'object/Conversation.php'; require_once 'object/Item.php'; $conv = new Conversation($mode, $preview); // 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) { if ($arr_blocked) { $blocked = false; foreach ($arr_blocked as $b) { if ($b && link_compare($item['author-link'], $b)) { $blocked = true; break; } } if ($blocked) { continue; } } // Can we put this after the visibility check? like_puller($a, $item, $alike, 'like'); like_puller($a, $item, $dlike, 'dislike'); // Only add what is visible if ($item['network'] === NETWORK_MAIL && local_user() != $item['uid']) { continue; } if (!visible_activity($item)) { continue; } call_hooks('display_item', $arr); $item['pagedrop'] = $page_dropping; if ($item['id'] == $item['parent']) { $item_object = new Item($item); $conv->add_thread($item_object); } } $threads = $conv->get_template_data($alike, $dlike); if (!$threads) { logger('[ERROR] conversation : Failed to get template data.', LOGGER_DEBUG); $threads = array(); } } } $o = replace_macros($page_template, array('$baseurl' => $a->get_baseurl($ssl_state), '$return_path' => $a->query_string, '$live_update' => $live_update_div, '$remove' => t('remove'), '$mode' => $mode, '$user' => $a->user, '$threads' => $threads, '$dropping' => $page_dropping && feature_enabled(local_user(), 'multi_delete') ? t('Delete Selected Items') : False)); return $o; }
/** * "Render" a conversation or list of items for HTML display. * There are two major forms of display: * - Sequential or unthreaded ("New Item View" or search results) * - conversation view * The $mode parameter decides between the various renderings and also * figures out how to determine page owner and other contextual items * that are based on unique features of the calling module. * */ function conversation(&$a, $items, $mode, $update, $preview = false) { require_once 'bbcode.php'; $profile_owner = 0; $page_writeable = false; if ($mode === 'network') { $profile_owner = local_user(); $page_writeable = true; } if ($mode === 'profile') { $profile_owner = $a->profile['profile_uid']; $page_writeable = can_write_wall($a, $profile_owner); } if ($mode === 'notes') { $profile_owner = local_user(); $page_writeable = true; } if ($mode === 'display') { $profile_owner = $a->profile['uid']; $page_writeable = can_write_wall($a, $profile_owner); } if ($mode === 'community') { $profile_owner = 0; $page_writeable = false; } if ($update) { $return_url = $_SESSION['return_url']; } else { $return_url = $_SESSION['return_url'] = $a->cmd; } load_contact_links(local_user()); $cmnt_tpl = get_markup_template('comment_item.tpl'); $tpl = get_markup_template('wall_item.tpl'); $wallwall = get_markup_template('wallwall_item.tpl'); $hide_comments_tpl = get_markup_template('hide_comments.tpl'); $alike = array(); $dlike = array(); // array with html for each thread (parent+comments) $threads = array(); $threadsid = -1; if (count($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'); foreach ($items as $item) { $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']; } $sp = false; $profile_link = best_link_url($item, $sp); if ($sp) { $sparkle = ' sparkle'; } if ($profile_link === 'mailbox') { $profile_link = ''; } $normalised = normalise_link(strlen($item['author-link']) ? $item['author-link'] : $item['url']); if ($normalised != 'mailbox' && x($a->contacts[$normalised])) { $profile_avatar = $a->contacts[$normalised]['thumb']; } else { $profile_avatar = strlen($item['author-avatar']) ? $item['author-avatar'] : $item['thumb']; } $location = $item['location'] ? '<a target="map" title="' . $item['location'] . '" href="http://maps.google.com/?q=' . urlencode($item['location']) . '">' . $item['location'] . '</a>' : ''; $coord = $item['coord'] ? '<a target="map" title="' . $item['coord'] . '" href="http://maps.google.com/?q=' . urlencode($item['coord']) . '">' . $item['coord'] . '</a>' : ''; if ($coord) { if ($location) { $location .= '<br /><span class="smalltext">(' . $coord . ')</span>'; } else { $location = '<span class="smalltext">' . $coord . '</span>'; } } localize_item($item); if ($mode === 'network-new') { $dropping = true; } else { $dropping = false; } $drop = array('dropping' => $dropping, 'select' => t('Select'), 'delete' => t('Delete')); $star = false; $isstarred = "unstarred"; $lock = false; $likebuttons = false; $shareable = false; $body = prepare_body($item, true); $tmp_item = replace_macros($tpl, array('$id' => $item['item_id'], '$linktitle' => sprintf(t('View %s\'s profile @ %s'), $profile_name, strlen($item['author-link']) ? $item['author-link'] : $item['url']), '$profile_url' => $profile_link, '$item_photo_menu' => item_photo_menu($item), '$name' => template_escape($profile_name), '$sparkle' => $sparkle, '$lock' => $lock, '$thumb' => $profile_avatar, '$title' => template_escape($item['title']), '$body' => template_escape($body), '$ago' => $item['app'] ? sprintf(t('%s from %s'), relative_date($item['created']), $item['app']) : relative_date($item['created']), '$lock' => $lock, '$location' => template_escape($location), '$indent' => '', '$owner_name' => template_escape($owner_name), '$owner_url' => $owner_url, '$owner_photo' => $owner_photo, '$plink' => get_plink($item), '$edpost' => false, '$isstarred' => $isstarred, '$star' => $star, '$drop' => $drop, '$vote' => $likebuttons, '$like' => '', '$dislike' => '', '$comment' => '', '$conv' => $preview ? '' : array('href' => $a->get_baseurl() . '/display/' . $nickname . '/' . $item['id'], 'title' => t('View in context')), '$wait' => t('Please wait'))); $arr = array('item' => $item, 'output' => $tmp_item); call_hooks('display_item', $arr); $threads[$threadsid]['id'] = $item['item_id']; $threads[$threadsid]['html'] .= $arr['output']; } } else { // Normal View // Figure out how many comments each parent has // (Comments all have gravity of 6) // Store the result in the $comments array $comments = array(); foreach ($items as $item) { if (intval($item['gravity']) == 6 && $item['id'] != $item['parent']) { if (!x($comments, $item['parent'])) { $comments[$item['parent']] = 1; } else { $comments[$item['parent']] += 1; } } } // map all the like/dislike activities for each parent item // Store these in the $alike and $dlike arrays foreach ($items as $item) { like_puller($a, $item, $alike, 'like'); like_puller($a, $item, $dlike, 'dislike'); } $comments_collapsed = false; $blowhard = 0; $blowhard_count = 0; foreach ($items as $item) { $comment = ''; $template = $tpl; $commentww = ''; $sparkle = ''; $owner_url = $owner_photo = $owner_name = ''; // We've already parsed out like/dislike for special treatment. We can ignore them now if ((activity_match($item['verb'], ACTIVITY_LIKE) || activity_match($item['verb'], ACTIVITY_DISLIKE)) && $item['id'] != $item['parent']) { continue; } $toplevelpost = $item['id'] == $item['parent'] ? true : false; $toplevelprivate = false; // Take care of author collapsing and comment collapsing // If a single author has more than 3 consecutive top-level posts, squash the remaining ones. // If there are more than two comments, squash all but the last 2. if ($toplevelpost) { $toplevelprivate = $toplevelpost && $item['private'] ? true : false; $item_writeable = $item['writable'] || $item['self'] ? true : false; /*if($blowhard == $item['cid'] && (! $item['self']) && ($mode != 'profile') && ($mode != 'notes')) { $blowhard_count ++; if($blowhard_count == 3) { $o .= '<div class="icollapse-wrapper fakelink" id="icollapse-wrapper-' . $item['parent'] . '" onclick="openClose(' . '\'icollapse-' . $item['parent'] . '\'); $(\'#icollapse-wrapper-' . $item['parent'] . '\').hide();" >' . t('See more posts like this') . '</div>' . '<div class="icollapse" id="icollapse-' . $item['parent'] . '" style="display: none;" >'; } } else { $blowhard = $item['cid']; if($blowhard_count >= 3) $o .= '</div>'; $blowhard_count = 0; }*/ $comments_seen = 0; $comments_collapsed = false; $threadsid++; $threads[$threadsid]['id'] = $item['item_id']; $threads[$threadsid]['html'] = ""; } else { // prevent private email from leaking into public conversation if (!$toplevelpost && !toplevelprivate && $item['private'] && $profile_owner != local_user()) { continue; } $comments_seen++; } $override_comment_box = $page_writeable && $item_writeable ? true : false; $show_comment_box = $page_writeable && $item_writeable && $comments_seen == $comments[$item['parent']] ? true : false; if ($comments[$item['parent']] > 2 && $comments_seen <= $comments[$item['parent']] - 2 && $item['gravity'] == 6) { if (!$comments_collapsed) { // IMPORTANT: the closing </div> in the hide_comments template // is supplied below in code. $threads[$threadsid]['html'] .= replace_macros($hide_comments_tpl, array('$id' => $item['parent'], '$num_comments' => sprintf(tt('%d comment', '%d comments', $comments[$item['parent']]), $comments[$item['parent']]), '$display' => 'none', '$hide_text' => t('show more'))); $comments_collapsed = true; } } if ($comments[$item['parent']] > 2 && $comments_seen == $comments[$item['parent']] - 1) { $threads[$threadsid]['html'] .= '</div>'; } $redirect_url = $a->get_baseurl() . '/redir/' . $item['cid']; $lock = $item['private'] || $item['uid'] == local_user() && (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) ? t('Private Message') : false; // Top-level wall post not written by the wall owner (wall-to-wall) // First figure out who owns it. $osparkle = ''; if ($toplevelpost && !$item['self'] && $mode !== 'profile') { if ($item['wall']) { // On the network page, I am the owner. On the display page it will be the profile owner. // This will have been stored in $a->page_contact by our calling page. // Put this person on the left of the wall-to-wall notice. $owner_url = $a->page_contact['url']; $owner_photo = $a->page_contact['thumb']; $owner_name = $a->page_contact['name']; $template = $wallwall; $commentww = 'ww'; } if (!$item['wall'] && strlen($item['owner-link']) && $item['owner-link'] != $item['author-link']) { // Could be anybody. $owner_url = $item['owner-link']; $owner_photo = $item['owner-avatar']; $owner_name = $item['owner-name']; $template = $wallwall; $commentww = 'ww'; // If it is our contact, use a friendly redirect link if (link_compare($item['owner-link'], $item['url']) && $item['network'] === 'dfrn') { $owner_url = $redirect_url; $osparkle = ' sparkle'; } } } $likebuttons = ''; $shareable = $profile_owner == local_user() && $mode != 'display' && !$item['private'] ? true : false; if ($page_writeable) { if ($toplevelpost) { $likebuttons = array('like' => array(t("I like this (toggle)"), t("like")), 'dislike' => array(t("I don't like this (toggle)"), t("dislike"))); if ($shareable) { $likebuttons['share'] = array(t('Share this'), t('share')); } } if ($show_comment_box || $show_comment_box == false && $override_comment_box == false && $item['last-child']) { $comment = replace_macros($cmnt_tpl, array('$return_path' => '', '$jsreload' => $mode === 'display' ? $_SESSION['return_url'] : '', '$type' => $mode === 'profile' ? 'wall-comment' : 'net-comment', '$id' => $item['item_id'], '$parent' => $item['parent'], '$profile_uid' => $profile_owner, '$mylink' => $a->contact['url'], '$mytitle' => t('This is you'), '$myphoto' => $a->contact['thumb'], '$comment' => t('Comment'), '$submit' => t('Submit'), '$preview' => t('Preview'), '$ww' => $mode === 'network' ? $commentww : '')); } } $edpost = $profile_owner == local_user() && $toplevelpost && intval($item['wall']) == 1 || $mode === 'notes' ? array($a->get_baseurl() . "/editpost/" . $item['id'], t("Edit")) : False; $drop = ''; $dropping = false; if (intval($item['contact-id']) && $item['contact-id'] == remote_user() || $item['uid'] == local_user()) { $dropping = true; } $drop = array('dropping' => $dropping, 'select' => t('Select'), 'delete' => t('Delete')); $star = false; $isstarred = "unstarred"; if ($profile_owner == local_user() && $toplevelpost) { $isstarred = $item['starred'] ? "starred" : "unstarred"; $star = array('do' => t("add star"), 'undo' => t("remove star"), 'toggle' => t("toggle star status"), 'classdo' => $item['starred'] ? "hidden" : "", 'classundo' => $item['starred'] ? "" : "hidden", 'starred' => t('starred'), 'tagger' => t("add tag"), 'classtagger' => ""); } $photo = $item['photo']; $thumb = $item['thumb']; // Post was remotely authored. $diff_author = link_compare($item['url'], $item['author-link']) ? false : true; $profile_name = strlen($item['author-name']) && $diff_author ? $item['author-name'] : $item['name']; if ($item['author-link'] && !$item['author-name']) { $profile_name = $item['author-link']; } $sp = false; $profile_link = best_link_url($item, $sp); if ($sp) { $sparkle = ' sparkle'; } if ($profile_link === 'mailbox') { $profile_link = ''; } $normalised = normalise_link(strlen($item['author-link']) ? $item['author-link'] : $item['url']); if ($normalised != 'mailbox' && x($a->contacts, $normalised)) { $profile_avatar = $a->contacts[$normalised]['thumb']; } else { $profile_avatar = strlen($item['author-avatar']) && $diff_author ? $item['author-avatar'] : $thumb; } $like = x($alike, $item['id']) ? format_like($alike[$item['id']], $alike[$item['id'] . '-l'], 'like', $item['id']) : ''; $dislike = x($dlike, $item['id']) ? format_like($dlike[$item['id']], $dlike[$item['id'] . '-l'], 'dislike', $item['id']) : ''; $location = $item['location'] ? '<a target="map" title="' . $item['location'] . '" href="http://maps.google.com/?q=' . urlencode($item['location']) . '">' . $item['location'] . '</a>' : ''; $coord = $item['coord'] ? '<a target="map" title="' . $item['coord'] . '" href="http://maps.google.com/?q=' . urlencode($item['coord']) . '">' . $item['coord'] . '</a>' : ''; if ($coord) { if ($location) { $location .= '<br /><span class="smalltext">(' . $coord . ')</span>'; } else { $location = '<span class="smalltext">' . $coord . '</span>'; } } $indent = $toplevelpost ? '' : ' comment'; if (strcmp(datetime_convert('UTC', 'UTC', $item['created']), datetime_convert('UTC', 'UTC', 'now - 12 hours')) > 0) { $indent .= ' shiny'; } // localize_item($item); $tags = array(); foreach (explode(',', $item['tag']) as $tag) { $tag = trim($tag); if ($tag != "") { $tags[] = bbcode($tag); } } // Build the HTML $body = prepare_body($item, true); $tmp_item = replace_macros($template, array('$type' => implode("", array_slice(split("/", $item['verb']), -1)), '$tags' => $tags, '$body' => template_escape($body), '$id' => $item['item_id'], '$linktitle' => sprintf(t('View %s\'s profile @ %s'), $profile_name, strlen($item['author-link']) ? $item['author-link'] : $item['url']), '$olinktitle' => sprintf(t('View %s\'s profile @ %s'), $profile_name, strlen($item['owner-link']) ? $item['owner-link'] : $item['url']), '$to' => t('to'), '$wall' => t('Wall-to-Wall'), '$vwall' => t('via Wall-To-Wall:'), '$profile_url' => $profile_link, '$item_photo_menu' => item_photo_menu($item), '$name' => template_escape($profile_name), '$thumb' => $profile_avatar, '$osparkle' => $osparkle, '$sparkle' => $sparkle, '$title' => template_escape($item['title']), '$ago' => $item['app'] ? sprintf(t('%s from %s'), relative_date($item['created']), $item['app']) : relative_date($item['created']), '$lock' => $lock, '$location' => template_escape($location), '$indent' => $indent, '$owner_url' => $owner_url, '$owner_photo' => $owner_photo, '$owner_name' => template_escape($owner_name), '$plink' => get_plink($item), '$edpost' => $edpost, '$isstarred' => $isstarred, '$star' => $star, '$drop' => $drop, '$vote' => $likebuttons, '$like' => $like, '$dislike' => $dislike, '$comment' => $comment, '$wait' => t('Please wait'))); $arr = array('item' => $item, 'output' => $tmp_item); call_hooks('display_item', $arr); $threads[$threadsid]['html'] .= $arr['output']; } } } $page_template = get_markup_template("conversation.tpl"); $o .= replace_macros($page_template, array('$threads' => $threads, '$dropping' => $dropping ? t('Delete Selected Items') : False)); return $o; }
function prepare_page($item) { $a = get_app(); $naked = get_pconfig($item['uid'], 'system', 'nakedpage') ? 1 : 0; $observer = $a->get_observer(); //240 chars is the longest we can have before we start hitting problems with suhosin sites $preview = substr(urlencode($item['body']), 0, 240); $link = z_root() . '/' . $a->cmd; if (array_key_exists('webpage', $a->layout) && array_key_exists('authored', $a->layout['webpage'])) { if ($a->layout['webpage']['authored'] === 'none') { $naked = 1; } // ... other possible options } // prepare_body calls unobscure() as a side effect. Do it here so that // the template will get passed an unobscured title. $body = prepare_body($item, true); $tpl = get_pconfig($item['uid'], 'system', 'pagetemplate'); if (!$tpl) { $tpl = 'page_display.tpl'; } return replace_macros(get_markup_template($tpl), array('$author' => $naked ? '' : $item['author']['xchan_name'], '$auth_url' => $naked ? '' : zid($item['author']['xchan_url']), '$date' => $naked ? '' : datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'Y-m-d H:i'), '$title' => smilies(bbcode($item['title'])), '$body' => $body, '$preview' => $preview, '$link' => $link)); }
function notifier_run($argv, $argc) { global $a, $db; if (is_null($a)) { $a = new App(); } if (is_null($db)) { @(include ".htconfig.php"); require_once "dba.php"; $db = new dba($db_host, $db_user, $db_pass, $db_data); unset($db_host, $db_user, $db_pass, $db_data); } require_once "session.php"; require_once "datetime.php"; require_once 'include/items.php'; require_once 'include/bbcode.php'; load_config('config'); load_config('system'); load_hooks(); if ($argc < 3) { return; } $a->set_baseurl(get_config('system', 'url')); logger('notifier: invoked: ' . print_r($argv, true)); $cmd = $argv[1]; switch ($cmd) { case 'mail': default: $item_id = intval($argv[2]); if (!$item_id) { return; } break; } $expire = false; $mail = false; $fsuggest = false; $top_level = false; $recipients = array(); $url_recipients = array(); $normal_mode = true; if ($cmd === 'mail') { $normal_mode = false; $mail = true; $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1", intval($item_id)); if (!count($message)) { return; } $uid = $message[0]['uid']; $recipients[] = $message[0]['contact-id']; $item = $message[0]; } elseif ($cmd === 'expire') { $normal_mode = false; $expire = true; $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1 \n\t\t\tAND `deleted` = 1 AND `changed` > UTC_TIMESTAMP() - INTERVAL 10 MINUTE", intval($item_id)); $uid = $item_id; $item_id = 0; if (!count($items)) { return; } } elseif ($cmd === 'suggest') { $normal_mode = false; $fsuggest = true; $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item_id)); if (!count($suggest)) { return; } $uid = $suggest[0]['uid']; $recipients[] = $suggest[0]['cid']; $item = $suggest[0]; } else { // find ancestors $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($item_id)); if (!count($r) || !intval($r[0]['parent'])) { return; } $target_item = $r[0]; $parent_id = intval($r[0]['parent']); $uid = $r[0]['uid']; $updated = $r[0]['edited']; if (!$parent_id) { return; } $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer` \n\t\t\tFROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d ORDER BY `id` ASC", intval($parent_id)); if (!count($items)) { return; } // avoid race condition with deleting entries if ($items[0]['deleted']) { foreach ($items as $item) { $item['deleted'] = 1; } } if (count($items) == 1 && $items[0]['id'] === $target_item['id'] && $items[0]['uri'] === $items[0]['parent-uri']) { logger('notifier: top level post'); $top_level = true; } } $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`, \n\t\t`user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`, \n\t\t`user`.`page-flags`, `user`.`prvnets`\n\t\tFROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid` \n\t\tWHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1", intval($uid)); if (!count($r)) { return; } $owner = $r[0]; $walltowall = $top_level && $owner['id'] != $items[0]['contact-id'] ? true : false; $hub = get_config('system', 'huburl'); // If this is a public conversation, notify the feed hub $public_message = true; // fill this in with a single salmon slap if applicable $slap = ''; if (!($mail || $fsuggest)) { require_once 'include/group.php'; $parent = $items[0]; // This is IMPORTANT!!!! // We will only send a "notify owner to relay" or followup message if the referenced post // originated on our system by virtue of having our hostname somewhere // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere. // if $parent['wall'] == 1 we will already have the parent message in our array // and we will relay the whole lot. // expire sends an entire group of expire messages and cannot be forwarded. // However the conversation owner will be a part of the conversation and will // be notified during this run. // Other DFRN conversation members will be alerted during polled updates. // Diaspora members currently are not notified of expirations, and other networks have // either limited or no ability to process deletions. We should at least fix Diaspora // by stringing togther an array of retractions and sending them onward. $localhost = $a->get_hostname(); if (strpos($localhost, ':')) { $localhost = substr($localhost, 0, strpos($localhost, ':')); } /** * * Be VERY CAREFUL if you make any changes to the following several lines. Seemingly innocuous changes * have been known to cause runaway conditions which affected several servers, along with * permissions issues. * */ $relay_to_owner = false; if (!$top_level && $parent['wall'] == 0 && !$expire && stristr($target_item['uri'], $localhost)) { $relay_to_owner = true; } if ($cmd === 'uplink' && intval($parent['forum_mode']) && !$top_level) { $relay_to_owner = true; } // until the 'origin' flag has been in use for several months // we will just use it as a fallback test // later we will be able to use it as the primary test of whether or not to relay. if (!$target_item['origin']) { $relay_to_owner = false; } if ($parent['origin']) { $relay_to_owner = false; } if ($relay_to_owner) { logger('notifier: followup', LOGGER_DEBUG); // local followup to remote post $followup = true; $public_message = false; // not public $conversant_str = dbesc($parent['contact-id']); } else { $followup = false; // don't send deletions onward for other people's stuff if ($target_item['deleted'] && !intval($target_item['wall'])) { logger('notifier: ignoring delete notification for non-wall item'); return; } if (strlen($parent['allow_cid']) || strlen($parent['allow_gid']) || strlen($parent['deny_cid']) || strlen($parent['deny_gid'])) { $public_message = false; // private recipients, not public } $allow_people = expand_acl($parent['allow_cid']); $allow_groups = expand_groups(expand_acl($parent['allow_gid'])); $deny_people = expand_acl($parent['deny_cid']); $deny_groups = expand_groups(expand_acl($parent['deny_gid'])); // if our parent is a forum, uplink to the origonal author causing // a delivery fork if (intval($parent['forum_mode']) && !$top_level && $cmd !== 'uplink') { proc_run('php', 'include/notifier', 'uplink', $item_id); } $conversants = array(); foreach ($items as $item) { $recipients[] = $item['contact-id']; $conversants[] = $item['contact-id']; // pull out additional tagged people to notify (if public message) if ($public_message && strlen($item['inform'])) { $people = explode(',', $item['inform']); foreach ($people as $person) { if (substr($person, 0, 4) === 'cid:') { $recipients[] = intval(substr($person, 4)); $conversants[] = intval(substr($person, 4)); } else { $url_recipients[] = substr($person, 4); } } } } logger('notifier: url_recipients' . print_r($url_recipients, true)); $conversants = array_unique($conversants); $recipients = array_unique(array_merge($recipients, $allow_people, $allow_groups)); $deny = array_unique(array_merge($deny_people, $deny_groups)); $recipients = array_diff($recipients, $deny); $conversant_str = dbesc(implode(', ', $conversants)); } $r = q("SELECT * FROM `contact` WHERE `id` IN ( {$conversant_str} ) AND `blocked` = 0 AND `pending` = 0"); if (count($r)) { $contacts = $r; } } $feed_template = get_markup_template('atom_feed.tpl'); $mail_template = get_markup_template('atom_mail.tpl'); $atom = ''; $slaps = array(); $hubxml = feed_hublinks(); $birthday = feed_birthday($owner['uid'], $owner['timezone']); if (strlen($birthday)) { $birthday = '<dfrn:birthday>' . xmlify($birthday) . '</dfrn:birthday>'; } $atom .= replace_macros($feed_template, array('$version' => xmlify(FRIENDICA_VERSION), '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner['nickname']), '$feed_title' => xmlify($owner['name']), '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', $updated . '+00:00', ATOM_TIME)), '$hub' => $hubxml, '$salmon' => '', '$name' => xmlify($owner['name']), '$profile_page' => xmlify($owner['url']), '$photo' => xmlify($owner['photo']), '$thumb' => xmlify($owner['thumb']), '$picdate' => xmlify(datetime_convert('UTC', 'UTC', $owner['avatar-date'] . '+00:00', ATOM_TIME)), '$uridate' => xmlify(datetime_convert('UTC', 'UTC', $owner['uri-date'] . '+00:00', ATOM_TIME)), '$namdate' => xmlify(datetime_convert('UTC', 'UTC', $owner['name-date'] . '+00:00', ATOM_TIME)), '$birthday' => $birthday)); if ($mail) { $public_message = false; // mail is not public $body = fix_private_photos($item['body'], $owner['uid']); $atom .= replace_macros($mail_template, array('$name' => xmlify($owner['name']), '$profile_page' => xmlify($owner['url']), '$thumb' => xmlify($owner['thumb']), '$item_id' => xmlify($item['uri']), '$subject' => xmlify($item['title']), '$created' => xmlify(datetime_convert('UTC', 'UTC', $item['created'] . '+00:00', ATOM_TIME)), '$content' => xmlify($body), '$parent_id' => xmlify($item['parent-uri']))); } elseif ($fsuggest) { $public_message = false; // suggestions are not public $sugg_template = get_markup_template('atom_suggest.tpl'); $atom .= replace_macros($sugg_template, array('$name' => xmlify($item['name']), '$url' => xmlify($item['url']), '$photo' => xmlify($item['photo']), '$request' => xmlify($item['request']), '$note' => xmlify($item['note']))); // We don't need this any more q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id'])); } else { if ($followup) { foreach ($items as $item) { // there is only one item if (!$item['parent']) { continue; } if ($item['id'] == $item_id) { logger('notifier: followup: item: ' . print_r($item, true), LOGGER_DATA); $slap = atom_entry($item, 'html', $owner, $owner, false); $atom .= atom_entry($item, 'text', $owner, $owner, false); } } } else { foreach ($items as $item) { if (!$item['parent']) { continue; } // private emails may be in included in public conversations. Filter them. if ($public_message && $item['private']) { continue; } $contact = get_item_contact($item, $contacts); if (!$contact) { continue; } if ($normal_mode) { // we only need the current item, but include the parent because without it // older sites without a corresponding dfrn_notify change may do the wrong thing. if ($item_id == $item['id'] || $item['id'] == $item['parent']) { $atom .= atom_entry($item, 'text', $contact, $owner, true); } } else { $atom .= atom_entry($item, 'text', $contact, $owner, true); } if ($top_level && $public_message && $item['author-link'] === $item['owner-link'] && !$expire) { $slaps[] = atom_entry($item, 'html', $contact, $owner, true); } } } } $atom .= '</feed>' . "\r\n"; logger('notifier: ' . $atom, LOGGER_DATA); logger('notifier: slaps: ' . print_r($slaps, true), LOGGER_DATA); // If this is a public message and pubmail is set on the parent, include all your email contacts $mail_disabled = function_exists('imap_open') && !get_config('system', 'imap_disabled') ? 0 : 1; if (!$mail_disabled) { if (!strlen($target_item['allow_cid']) && !strlen($target_item['allow_gid']) && !strlen($target_item['deny_cid']) && !strlen($target_item['deny_gid']) && intval($target_item['pubmail'])) { $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `network` = '%s'", intval($uid), dbesc(NETWORK_MAIL)); if (count($r)) { foreach ($r as $rr) { $recipients[] = $rr['id']; } } } } if ($followup) { $recip_str = $parent['contact-id']; } else { $recip_str = implode(', ', $recipients); } $r = q("SELECT * FROM `contact` WHERE `id` IN ( %s ) AND `blocked` = 0 AND `pending` = 0 ", dbesc($recip_str)); require_once 'include/salmon.php'; $interval = get_config('system', 'delivery_interval') === false ? 2 : intval(get_config('system', 'delivery_interval')); // delivery loop if (count($r)) { foreach ($r as $contact) { if (!$mail && !$fsuggest && !$followup && !$contact['self']) { if ($contact['network'] === NETWORK_DIASPORA && $public_message) { continue; } q("insert into deliverq ( `cmd`,`item`,`contact` ) values ('%s', %d, %d )", dbesc($cmd), intval($item_id), intval($contact['id'])); } } foreach ($r as $contact) { if ($contact['self']) { continue; } // potentially more than one recipient. Start a new process and space them out a bit. // we will deliver single recipient types of message and email receipients here. if (!$mail && !$fsuggest && !$followup) { proc_run('php', 'include/delivery.php', $cmd, $item_id, $contact['id']); if ($interval) { @time_sleep_until(microtime(true) + (double) $interval); } continue; } $deliver_status = 0; logger("main delivery by notifier: followup={$followup} mail={$mail} fsuggest={$fsuggest}"); switch ($contact['network']) { case NETWORK_DFRN: // perform local delivery if we are on the same site $basepath = implode('/', array_slice(explode('/', $contact['url']), 0, 3)); if (link_compare($basepath, $a->get_baseurl())) { $nickname = basename($contact['url']); if ($contact['issued-id']) { $sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id'])); } else { $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id'])); } $x = q("SELECT\t`contact`.*, `contact`.`uid` AS `importer_uid`, \n\t\t\t\t\t\t\t`contact`.`pubkey` AS `cpubkey`, \n\t\t\t\t\t\t\t`contact`.`prvkey` AS `cprvkey`, \n\t\t\t\t\t\t\t`contact`.`thumb` AS `thumb`, \n\t\t\t\t\t\t\t`contact`.`url` as `url`,\n\t\t\t\t\t\t\t`contact`.`name` as `senderName`,\n\t\t\t\t\t\t\t`user`.* \n\t\t\t\t\t\t\tFROM `contact` \n\t\t\t\t\t\t\tLEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` \n\t\t\t\t\t\t\tWHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0\n\t\t\t\t\t\t\tAND `contact`.`network` = '%s' AND `user`.`nickname` = '%s'\n\t\t\t\t\t\t\t{$sql_extra}\n\t\t\t\t\t\t\tAND `user`.`account_expired` = 0 LIMIT 1", dbesc(NETWORK_DFRN), dbesc($nickname)); if (count($x)) { require_once 'library/simplepie/simplepie.inc'; logger('mod-delivery: local delivery'); local_delivery($x[0], $atom); break; } } logger('notifier: dfrndelivery: ' . $contact['name']); $deliver_status = dfrn_deliver($owner, $contact, $atom); logger('notifier: dfrn_delivery returns ' . $deliver_status); if ($deliver_status == -1) { logger('notifier: delivery failed: queuing message'); // queue message for redelivery add_to_queue($contact['id'], NETWORK_DFRN, $atom); } break; case NETWORK_OSTATUS: // Do not send to otatus if we are not configured to send to public networks if ($owner['prvnets']) { break; } if (get_config('system', 'ostatus_disabled') || get_config('system', 'dfrn_only')) { break; } if ($followup && $contact['notify']) { logger('notifier: slapdelivery: ' . $contact['name']); $deliver_status = slapper($owner, $contact['notify'], $slap); if ($deliver_status == -1) { // queue message for redelivery add_to_queue($contact['id'], NETWORK_OSTATUS, $slap); } } else { // only send salmon if public - e.g. if it's ok to notify // a public hub, it's ok to send a salmon if (count($slaps) && $public_message && !$expire) { logger('notifier: slapdelivery: ' . $contact['name']); foreach ($slaps as $slappy) { if ($contact['notify']) { $deliver_status = slapper($owner, $contact['notify'], $slappy); if ($deliver_status == -1) { // queue message for redelivery add_to_queue($contact['id'], NETWORK_OSTATUS, $slappy); } } } } } break; case NETWORK_MAIL: if (get_config('system', 'dfrn_only')) { break; } // WARNING: does not currently convert to RFC2047 header encodings, etc. $addr = $contact['addr']; if (!strlen($addr)) { break; } if ($cmd === 'wall-new' || $cmd === 'comment-new') { $it = null; if ($cmd === 'wall-new') { $it = $items[0]; } else { $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($argv[2]), intval($uid)); if (count($r)) { $it = $r[0]; } } if (!$it) { break; } $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($uid)); if (!count($local_user)) { break; } $reply_to = ''; $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1", intval($uid)); if ($r1 && $r1[0]['reply_to']) { $reply_to = $r1[0]['reply_to']; } $subject = $it['title'] ? $it['title'] : t("(no subject)"); $headers = 'From: ' . $local_user[0]['username'] . ' <' . $local_user[0]['email'] . '>' . "\n"; if ($reply_to) { $headers .= 'Reply-to: ' . $reply_to . "\n"; } $headers .= 'Message-id: <' . $it['uri'] . '>' . "\n"; if ($it['uri'] !== $it['parent-uri']) { $header .= 'References: <' . $it['parent-uri'] . '>' . "\n"; if (!strlen($it['title'])) { $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' LIMIT 1", dbesc($it['parent-uri'])); if (count($r)) { $subtitle = $r[0]['title']; if ($subtitle) { if (strncasecmp($subtitle, 'RE:', 3)) { $subject = $subtitle; } else { $subject = 'Re: ' . $subtitle; } } } } } $headers .= 'MIME-Version: 1.0' . "\n"; $headers .= 'Content-Type: text/html; charset=UTF-8' . "\n"; $headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n"; $html = prepare_body($it); $message = '<html><body>' . $html . '</body></html>'; logger('notifier: email delivery to ' . $addr); mail($addr, $subject, $message, $headers); } break; case NETWORK_DIASPORA: require_once 'include/diaspora.php'; if (get_config('system', 'dfrn_only') || !get_config('system', 'diaspora_enabled')) { break; } if ($mail) { diaspora_send_mail($item, $owner, $contact); break; } if (!$normal_mode) { break; } // special handling for followup to public post // all other public posts processed as public batches further below if ($public_message) { if ($followup) { diaspora_send_followup($target_item, $owner, $contact, true); } break; } if (!$contact['pubkey']) { break; } if ($target_item['verb'] === ACTIVITY_DISLIKE) { // unsupported break; } elseif ($target_item['deleted'] && $target_item['verb'] !== ACTIVITY_LIKE) { // diaspora delete, diaspora_send_retraction($target_item, $owner, $contact); break; } elseif ($followup) { // send comments, likes and retractions of likes to owner to relay diaspora_send_followup($target_item, $owner, $contact); break; } elseif ($target_item['parent'] != $target_item['id']) { // we are the relay - send comments, likes and unlikes to our conversants diaspora_send_relay($target_item, $owner, $contact); break; } elseif ($top_level && !$walltowall) { // currently no workable solution for sending walltowall diaspora_send_status($target_item, $owner, $contact); break; } break; case NETWORK_FEED: case NETWORK_FACEBOOK: if (get_config('system', 'dfrn_only')) { break; } default: break; } } } // send additional slaps to mentioned remote tags (@foo@example.com) if ($slap && count($url_recipients) && ($followup || $top_level) && $public_message && !$expire) { if (!get_config('system', 'dfrn_only')) { foreach ($url_recipients as $url) { if ($url) { logger('notifier: urldelivery: ' . $url); $deliver_status = slapper($owner, $url, $slap); // TODO: redeliver/queue these items on failure, though there is no contact record } } } } if ($public_message) { $r1 = q("SELECT DISTINCT(`batch`), `id`, `name`,`network` FROM `contact` WHERE `network` = '%s' \n\t\t\tAND `uid` = %d AND `rel` != %d group by `batch` ORDER BY rand() ", dbesc(NETWORK_DIASPORA), intval($owner['uid']), intval(CONTACT_IS_SHARING)); $r2 = q("SELECT `id`, `name`,`network` FROM `contact` \n\t\t\tWHERE `network` = '%s' AND `uid` = %d AND `blocked` = 0 AND `pending` = 0\n\t\t\tAND `rel` != %d order by rand() ", dbesc(NETWORK_DFRN), intval($owner['uid']), intval(CONTACT_IS_SHARING)); $r = array_merge($r2, $r1); if (count($r)) { logger('pubdeliver: ' . print_r($r, true), LOGGER_DEBUG); // throw everything into the queue in case we get killed foreach ($r as $rr) { if (!$mail && !$fsuggest && !$followup) { q("insert into deliverq ( `cmd`,`item`,`contact` ) values ('%s', %d, %d )", dbesc($cmd), intval($item_id), intval($rr['id'])); } } foreach ($r as $rr) { // except for Diaspora batch jobs // Don't deliver to folks who have already been delivered to if ($rr['network'] !== NETWORK_DIASPORA && in_array($rr['id'], $conversants)) { logger('notifier: already delivered id=' . $rr['id']); continue; } if (!$mail && !$fsuggest && !$followup) { logger('notifier: delivery agent: ' . $rr['name'] . ' ' . $rr['id']); proc_run('php', 'include/delivery.php', $cmd, $item_id, $rr['id']); if ($interval) { @time_sleep_until(microtime(true) + (double) $interval); } } } } if (strlen($hub)) { $hubs = explode(',', $hub); if (count($hubs)) { foreach ($hubs as $h) { $h = trim($h); if (!strlen($h)) { continue; } $params = 'hub.mode=publish&hub.url=' . urlencode($a->get_baseurl() . '/dfrn_poll/' . $owner['nickname']); post_url($h, $params); logger('pubsub: publish: ' . $h . ' ' . $params . ' returned ' . $a->get_curl_code()); if (count($hubs) > 1) { sleep(7); } // try and avoid multiple hubs responding at precisely the same time } } } } if ($normal_mode) { call_hooks('notifier_normal', $target_item); } call_hooks('notifier_end', $target_item); return; }
function email_send($addr, $subject, $headers, $item) { //$headers .= 'MIME-Version: 1.0' . "\n"; //$headers .= 'Content-Type: text/html; charset=UTF-8' . "\n"; //$headers .= 'Content-Type: text/plain; charset=UTF-8' . "\n"; //$headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n"; $part = uniqid("", true); $html = prepare_body($item); $headers .= "Mime-Version: 1.0\n"; $headers .= 'Content-Type: multipart/alternative; boundary="=_' . $part . '"' . "\n\n"; $body = "\n--=_" . $part . "\n"; $body .= "Content-Transfer-Encoding: 8bit\n"; $body .= "Content-Type: text/plain; charset=utf-8; format=flowed\n\n"; $body .= html2plain($html) . "\n"; $body .= "--=_" . $part . "\n"; $body .= "Content-Transfer-Encoding: 8bit\n"; $body .= "Content-Type: text/html; charset=utf-8\n\n"; $body .= '<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">' . $html . "</body></html>\n"; $body .= "--=_" . $part . "--"; //$message = '<html><body>' . $html . '</body></html>'; //$message = html2plain($html); logger('notifier: email delivery to ' . $addr); mail($addr, $subject, $body, $headers); }
function item_post(&$a) { if (!local_user() && !remote_user() && !x($_REQUEST, 'commenter')) { return; } require_once 'include/security.php'; $uid = local_user(); if (x($_REQUEST, 'dropitems')) { $arr_drop = explode(',', $_REQUEST['dropitems']); drop_items($arr_drop); $json = array('success' => 1); echo json_encode($json); killme(); } call_hooks('post_local_start', $_REQUEST); // logger('postinput ' . file_get_contents('php://input')); logger('postvars ' . print_r($_REQUEST, true), LOGGER_DATA); $api_source = x($_REQUEST, 'api_source') && $_REQUEST['api_source'] ? true : false; $message_id = x($_REQUEST, 'message_id') && $api_source ? strip_tags($_REQUEST['message_id']) : ''; $return_path = x($_REQUEST, 'return') ? $_REQUEST['return'] : ''; $preview = x($_REQUEST, 'preview') ? intval($_REQUEST['preview']) : 0; // Check for doubly-submitted posts, and reject duplicates // Note that we have to ignore previews, otherwise nothing will post // after it's been previewed if (!$preview && x($_REQUEST['post_id_random'])) { if (x($_SESSION['post-random']) && $_SESSION['post-random'] == $_REQUEST['post_id_random']) { logger("item post: duplicate post", LOGGER_DEBUG); item_post_return($a->get_baseurl(), $api_source, $return_path); } else { $_SESSION['post-random'] = $_REQUEST['post_id_random']; } } /** * Is this a reply to something? */ $parent = x($_REQUEST, 'parent') ? intval($_REQUEST['parent']) : 0; $parent_uri = x($_REQUEST, 'parent_uri') ? trim($_REQUEST['parent_uri']) : ''; $parent_item = null; $parent_contact = null; $thr_parent = ''; $parid = 0; $r = false; $objecttype = null; if ($parent || $parent_uri) { $objecttype = ACTIVITY_OBJ_COMMENT; if (!x($_REQUEST, 'type')) { $_REQUEST['type'] = 'net-comment'; } if ($parent) { $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($parent)); } elseif ($parent_uri && local_user()) { // This is coming from an API source, and we are logged in $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($parent_uri), intval(local_user())); } // if this isn't the real parent of the conversation, find it if ($r !== false && count($r)) { $parid = $r[0]['parent']; $parent_uri = $r[0]['uri']; if ($r[0]['id'] != $r[0]['parent']) { $r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1", intval($parid)); } } if ($r === false || !count($r)) { notice(t('Unable to locate original post.') . EOL); if (x($_REQUEST, 'return')) { goaway($a->get_baseurl() . "/" . $return_path); } killme(); } $parent_item = $r[0]; $parent = $r[0]['id']; // multi-level threading - preserve the info but re-parent to our single level threading //if(($parid) && ($parid != $parent)) $thr_parent = $parent_uri; if ($parent_item['contact-id'] && $uid) { $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($parent_item['contact-id']), intval($uid)); if (count($r)) { $parent_contact = $r[0]; // If the contact id doesn't fit with the contact, then set the contact to null $thrparent = q("SELECT `author-link`, `network` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($thr_parent)); if (count($thrparent) and $thrparent[0]["network"] === NETWORK_OSTATUS and normalise_link($parent_contact["url"]) != normalise_link($thrparent[0]["author-link"])) { $parent_contact = null; require_once "include/Scrape.php"; $probed_contact = probe_url($thrparent[0]["author-link"]); if ($probed_contact["network"] != NETWORK_FEED) { $parent_contact = $probed_contact; $parent_contact["nurl"] = normalise_link($probed_contact["url"]); $parent_contact["thumb"] = $probed_contact["photo"]; $parent_contact["micro"] = $probed_contact["photo"]; } logger('parent contact: ' . print_r($parent_contact, true), LOGGER_DEBUG); } else { logger('no contact found: ' . print_r($thrparent, true), LOGGER_DEBUG); } } } } if ($parent) { logger('mod_item: item_post parent=' . $parent); } $profile_uid = x($_REQUEST, 'profile_uid') ? intval($_REQUEST['profile_uid']) : 0; $post_id = x($_REQUEST, 'post_id') ? intval($_REQUEST['post_id']) : 0; $app = x($_REQUEST, 'source') ? strip_tags($_REQUEST['source']) : ''; $extid = x($_REQUEST, 'extid') ? strip_tags($_REQUEST['extid']) : ''; $allow_moderated = false; // here is where we are going to check for permission to post a moderated comment. // First check that the parent exists and it is a wall item. if (x($_REQUEST, 'commenter') && (!$parent || !$parent_item['wall'])) { notice(t('Permission denied.') . EOL); if (x($_REQUEST, 'return')) { goaway($a->get_baseurl() . "/" . $return_path); } killme(); } // Now check that it is a page_type of PAGE_BLOG, and that valid personal details // have been provided, and run any anti-spam plugins // TODO if (!can_write_wall($a, $profile_uid) && !$allow_moderated) { notice(t('Permission denied.') . EOL); if (x($_REQUEST, 'return')) { goaway($a->get_baseurl() . "/" . $return_path); } killme(); } // is this an edited post? $orig_post = null; if ($post_id) { $i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($post_id)); if (!count($i)) { killme(); } $orig_post = $i[0]; } $user = null; $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($profile_uid)); if (count($r)) { $user = $r[0]; } if ($orig_post) { $str_group_allow = $orig_post['allow_gid']; $str_contact_allow = $orig_post['allow_cid']; $str_group_deny = $orig_post['deny_gid']; $str_contact_deny = $orig_post['deny_cid']; $location = $orig_post['location']; $coord = $orig_post['coord']; $verb = $orig_post['verb']; $objecttype = $orig_post['object-type']; $emailcc = $orig_post['emailcc']; $app = $orig_post['app']; $categories = $orig_post['file']; $title = notags(trim($_REQUEST['title'])); $body = escape_tags(trim($_REQUEST['body'])); $private = $orig_post['private']; $pubmail_enable = $orig_post['pubmail']; $network = $orig_post['network']; $guid = $orig_post['guid']; $extid = $orig_post['extid']; } else { // if coming from the API and no privacy settings are set, // use the user default permissions - as they won't have // been supplied via a form. if ($api_source && !array_key_exists('contact_allow', $_REQUEST) && !array_key_exists('group_allow', $_REQUEST) && !array_key_exists('contact_deny', $_REQUEST) && !array_key_exists('group_deny', $_REQUEST)) { $str_group_allow = $user['allow_gid']; $str_contact_allow = $user['allow_cid']; $str_group_deny = $user['deny_gid']; $str_contact_deny = $user['deny_cid']; } else { // use the posted permissions $str_group_allow = perms2str($_REQUEST['group_allow']); $str_contact_allow = perms2str($_REQUEST['contact_allow']); $str_group_deny = perms2str($_REQUEST['group_deny']); $str_contact_deny = perms2str($_REQUEST['contact_deny']); } $title = notags(trim($_REQUEST['title'])); $location = notags(trim($_REQUEST['location'])); $coord = notags(trim($_REQUEST['coord'])); $verb = notags(trim($_REQUEST['verb'])); $emailcc = notags(trim($_REQUEST['emailcc'])); $body = escape_tags(trim($_REQUEST['body'])); $network = notags(trim($_REQUEST['network'])); $guid = get_guid(32); $naked_body = preg_replace('/\\[(.+?)\\]/', '', $body); if (version_compare(PHP_VERSION, '5.3.0', '>=')) { $l = new Text_LanguageDetect(); //$lng = $l->detectConfidence($naked_body); //$postopts = (($lng['language']) ? 'lang=' . $lng['language'] . ';' . $lng['confidence'] : ''); $lng = $l->detect($naked_body, 3); if (sizeof($lng) > 0) { $postopts = ""; foreach ($lng as $language => $score) { if ($postopts == "") { $postopts = "lang="; } else { $postopts .= ":"; } $postopts .= $language . ";" . $score; } } logger('mod_item: detect language' . print_r($lng, true) . $naked_body, LOGGER_DATA); } else { $postopts = ''; } $private = strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny) ? 1 : 0; if ($user['hidewall']) { $private = 2; } // If this is a comment, set the permissions from the parent. if ($parent_item) { $private = 0; // for non native networks use the network of the original post as network of the item if ($parent_item['network'] != NETWORK_DIASPORA and $parent_item['network'] != NETWORK_OSTATUS and $network == "") { $network = $parent_item['network']; } if ($parent_item['private'] || strlen($parent_item['allow_cid']) || strlen($parent_item['allow_gid']) || strlen($parent_item['deny_cid']) || strlen($parent_item['deny_gid'])) { $private = $parent_item['private'] ? $parent_item['private'] : 1; } $str_contact_allow = $parent_item['allow_cid']; $str_group_allow = $parent_item['allow_gid']; $str_contact_deny = $parent_item['deny_cid']; $str_group_deny = $parent_item['deny_gid']; } $pubmail_enable = x($_REQUEST, 'pubmail_enable') && intval($_REQUEST['pubmail_enable']) && !$private ? 1 : 0; // if using the API, we won't see pubmail_enable - figure out if it should be set if ($api_source && $profile_uid && $profile_uid == local_user() && !$private) { $mail_disabled = function_exists('imap_open') && !get_config('system', 'imap_disabled') ? 0 : 1; if (!$mail_disabled) { $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1", intval(local_user())); if (count($r) && intval($r[0]['pubmail'])) { $pubmail_enabled = true; } } } if (!strlen($body)) { if ($preview) { killme(); } info(t('Empty post discarded.') . EOL); if (x($_REQUEST, 'return')) { goaway($a->get_baseurl() . "/" . $return_path); } killme(); } } if (strlen($categories)) { // get the "fileas" tags for this post $filedas = file_tag_file_to_list($categories, 'file'); } // save old and new categories, so we can determine what needs to be deleted from pconfig $categories_old = $categories; $categories = file_tag_list_to_file(trim($_REQUEST['category']), 'category'); $categories_new = $categories; if (strlen($filedas)) { // append the fileas stuff to the new categories list $categories .= file_tag_list_to_file($filedas, 'file'); } // Work around doubled linefeeds in Tinymce 3.5b2 // First figure out if it's a status post that would've been // created using tinymce. Otherwise leave it alone. /* $plaintext = (local_user() ? intval(get_pconfig(local_user(),'system','plaintext')) || !feature_enabled($profile_uid,'richtext') : 0); if((! $parent) && (! $api_source) && (! $plaintext)) { $body = fix_mce_lf($body); }*/ $plaintext = local_user() ? !feature_enabled($profile_uid, 'richtext') : 0; if (!$parent && !$api_source && !$plaintext) { $body = fix_mce_lf($body); } // get contact info for poster $author = null; $self = false; $contact_id = 0; if (local_user() && local_user() == $profile_uid) { $self = true; $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($_SESSION['uid'])); } elseif (remote_user()) { if (is_array($_SESSION['remote'])) { foreach ($_SESSION['remote'] as $v) { if ($v['uid'] == $profile_uid) { $contact_id = $v['cid']; break; } } } if ($contact_id) { $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($contact_id)); } } if (count($r)) { $author = $r[0]; $contact_id = $author['id']; } // get contact info for owner if ($profile_uid == local_user()) { $contact_record = $author; } else { $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($profile_uid)); if (count($r)) { $contact_record = $r[0]; } } $post_type = notags(trim($_REQUEST['type'])); if ($post_type === 'net-comment') { if ($parent_item !== null) { if ($parent_item['wall'] == 1) { $post_type = 'wall-comment'; } else { $post_type = 'remote-comment'; } } } /** * * When a photo was uploaded into the message using the (profile wall) ajax * uploader, The permissions are initially set to disallow anybody but the * owner from seeing it. This is because the permissions may not yet have been * set for the post. If it's private, the photo permissions should be set * appropriately. But we didn't know the final permissions on the post until * now. So now we'll look for links of uploaded messages that are in the * post and set them to the same permissions as the post itself. * */ $match = null; if (!$preview && preg_match_all("/\\[img([\\=0-9x]*?)\\](.*?)\\[\\/img\\]/", $body, $match)) { $images = $match[2]; if (count($images)) { $objecttype = ACTIVITY_OBJ_IMAGE; foreach ($images as $image) { if (!stristr($image, $a->get_baseurl() . '/photo/')) { continue; } $image_uri = substr($image, strrpos($image, '/') + 1); $image_uri = substr($image_uri, 0, strpos($image_uri, '-')); if (!strlen($image_uri)) { continue; } $srch = '<' . intval($contact_id) . '>'; $r = q("SELECT `id` FROM `photo` WHERE `allow_cid` = '%s' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = ''\n\t\t\t\t\tAND `resource-id` = '%s' AND `uid` = %d LIMIT 1", dbesc($srch), dbesc($image_uri), intval($profile_uid)); if (!count($r)) { continue; } $r = q("UPDATE `photo` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\tWHERE `resource-id` = '%s' AND `uid` = %d AND `album` = '%s' ", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), dbesc($image_uri), intval($profile_uid), dbesc(t('Wall Photos'))); } } } /** * Next link in any attachment references we find in the post. */ $match = false; if (!$preview && preg_match_all("/\\[attachment\\](.*?)\\[\\/attachment\\]/", $body, $match)) { $attaches = $match[1]; if (count($attaches)) { foreach ($attaches as $attach) { $r = q("SELECT * FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($attach)); if (count($r)) { $r = q("UPDATE `attach` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\t\tWHERE `uid` = %d AND `id` = %d", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), intval($profile_uid), intval($attach)); } } } } // embedded bookmark in post? set bookmark flag $bookmark = 0; if (preg_match_all("/\\[bookmark\\=([^\\]]*)\\](.*?)\\[\\/bookmark\\]/ism", $body, $match, PREG_SET_ORDER)) { $objecttype = ACTIVITY_OBJ_BOOKMARK; $bookmark = 1; } $body = bb_translate_video($body); /** * Fold multi-line [code] sequences */ $body = preg_replace('/\\[\\/code\\]\\s*\\[code\\]/ism', "\n", $body); $body = scale_external_images($body, false); // Setting the object type if not defined before if (!$objecttype) { $objecttype = ACTIVITY_OBJ_NOTE; // Default value require_once "include/plaintext.php"; $objectdata = get_attached_data($body); if ($post["type"] == "link") { $objecttype = ACTIVITY_OBJ_BOOKMARK; } elseif ($post["type"] == "video") { $objecttype = ACTIVITY_OBJ_VIDEO; } elseif ($post["type"] == "photo") { $objecttype = ACTIVITY_OBJ_IMAGE; } } /** * Look for any tags and linkify them */ $str_tags = ''; $inform = ''; $tags = get_tags($body); /** * add a statusnet style reply tag if the original post was from there * and we are replying, and there isn't one already */ if ($parent_contact && $parent_contact['network'] === NETWORK_OSTATUS && $parent_contact['nick'] && !in_array('@' . $parent_contact['nick'], $tags)) { $body = '@' . $parent_contact['nick'] . ' ' . $body; $tags[] = '@' . $parent_contact['nick']; } $tagged = array(); $private_forum = false; if (count($tags)) { foreach ($tags as $tag) { if (strpos($tag, '#') === 0) { continue; } // If we already tagged 'Robert Johnson', don't try and tag 'Robert'. // Robert Johnson should be first in the $tags array $fullnametagged = false; for ($x = 0; $x < count($tagged); $x++) { if (stristr($tagged[$x], $tag . ' ')) { $fullnametagged = true; break; } } if ($fullnametagged) { continue; } $success = handle_tag($a, $body, $inform, $str_tags, local_user() ? local_user() : $profile_uid, $tag, $network); if ($success['replaced']) { $tagged[] = $tag; } if (is_array($success['contact']) && intval($success['contact']['prv'])) { $private_forum = true; $private_id = $success['contact']['id']; } } } if ($private_forum && !$parent && !$private) { // we tagged a private forum in a top level post and the message was public. // Restrict it. $private = 1; $str_contact_allow = '<' . $private_id . '>'; } $attachments = ''; $match = false; if (preg_match_all('/(\\[attachment\\]([0-9]+)\\[\\/attachment\\])/', $body, $match)) { foreach ($match[2] as $mtch) { $r = q("SELECT `id`,`filename`,`filesize`,`filetype` FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($mtch)); if (count($r)) { if (strlen($attachments)) { $attachments .= ','; } $attachments .= '[attach]href="' . $a->get_baseurl() . '/attach/' . $r[0]['id'] . '" length="' . $r[0]['filesize'] . '" type="' . $r[0]['filetype'] . '" title="' . ($r[0]['filename'] ? $r[0]['filename'] : '') . '"[/attach]'; } $body = str_replace($match[1], '', $body); } } $wall = 0; if ($post_type === 'wall' || $post_type === 'wall-comment') { $wall = 1; } if (!strlen($verb)) { $verb = ACTIVITY_POST; } if ($network == "") { $network = NETWORK_DFRN; } $gravity = $parent ? 6 : 0; // even if the post arrived via API we are considering that it // originated on this site by default for determining relayability. $origin = x($_REQUEST, 'origin') ? intval($_REQUEST['origin']) : 1; $notify_type = $parent ? 'comment-new' : 'wall-new'; $uri = $message_id ? $message_id : item_new_uri($a->get_hostname(), $profile_uid); // Fallback so that we alway have a thr-parent if (!$thr_parent) { $thr_parent = $uri; } $datarray = array(); $datarray['uid'] = $profile_uid; $datarray['type'] = $post_type; $datarray['wall'] = $wall; $datarray['gravity'] = $gravity; $datarray['network'] = $network; $datarray['contact-id'] = $contact_id; $datarray['owner-name'] = $contact_record['name']; $datarray['owner-link'] = $contact_record['url']; $datarray['owner-avatar'] = $contact_record['thumb']; $datarray['author-name'] = $author['name']; $datarray['author-link'] = $author['url']; $datarray['author-avatar'] = $author['thumb']; $datarray['created'] = datetime_convert(); $datarray['edited'] = datetime_convert(); $datarray['commented'] = datetime_convert(); $datarray['received'] = datetime_convert(); $datarray['changed'] = datetime_convert(); $datarray['extid'] = $extid; $datarray['guid'] = $guid; $datarray['uri'] = $uri; $datarray['title'] = $title; $datarray['body'] = $body; $datarray['app'] = $app; $datarray['location'] = $location; $datarray['coord'] = $coord; $datarray['tag'] = $str_tags; $datarray['file'] = $categories; $datarray['inform'] = $inform; $datarray['verb'] = $verb; $datarray['object-type'] = $objecttype; $datarray['allow_cid'] = $str_contact_allow; $datarray['allow_gid'] = $str_group_allow; $datarray['deny_cid'] = $str_contact_deny; $datarray['deny_gid'] = $str_group_deny; $datarray['private'] = $private; $datarray['pubmail'] = $pubmail_enable; $datarray['attach'] = $attachments; $datarray['bookmark'] = intval($bookmark); $datarray['thr-parent'] = $thr_parent; $datarray['postopts'] = $postopts; $datarray['origin'] = $origin; $datarray['moderated'] = $allow_moderated; /** * These fields are for the convenience of plugins... * 'self' if true indicates the owner is posting on their own wall * If parent is 0 it is a top-level post. */ $datarray['parent'] = $parent; $datarray['self'] = $self; // $datarray['prvnets'] = $user['prvnets']; if ($orig_post) { $datarray['edit'] = true; } // Search for hashtags item_body_set_hashtags($datarray); // preview mode - prepare the body for display and send it via json if ($preview) { require_once 'include/conversation.php'; $o = conversation($a, array(array_merge($contact_record, $datarray)), 'search', false, true); logger('preview: ' . $o); echo json_encode(array('preview' => $o)); killme(); } call_hooks('post_local', $datarray); if (x($datarray, 'cancel')) { logger('mod_item: post cancelled by plugin.'); if ($return_path) { goaway($a->get_baseurl() . "/" . $return_path); } $json = array('cancel' => 1); if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) { $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload']; } echo json_encode($json); killme(); } // Fill the cache field put_item_in_cache($datarray); if ($orig_post) { $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `attach` = '%s', `file` = '%s', `rendered-html` = '%s', `rendered-hash` = '%s', `edited` = '%s', `changed` = '%s' WHERE `id` = %d AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc($datarray['attach']), dbesc($datarray['file']), dbesc($datarray['rendered-html']), dbesc($datarray['rendered-hash']), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($post_id), intval($profile_uid)); create_tags_from_item($post_id); create_files_from_item($post_id); update_thread($post_id); // update filetags in pconfig file_tag_update_pconfig($uid, $categories_old, $categories_new, 'category'); proc_run('php', "include/notifier.php", 'edit_post', "{$post_id}"); if (x($_REQUEST, 'return') && strlen($return_path)) { logger('return: ' . $return_path); goaway($a->get_baseurl() . "/" . $return_path); } killme(); } else { $post_id = 0; } $r = q("INSERT INTO `item` (`guid`, `extid`, `uid`,`type`,`wall`,`gravity`, `network`, `contact-id`,`owner-name`,`owner-link`,`owner-avatar`, `author-name`, `author-link`, `author-avatar`,\n\t\t`created`, `edited`, `commented`, `received`, `changed`, `uri`, `thr-parent`, `title`, `body`, `app`, `location`, `coord`, `tag`, `inform`, `verb`, `object-type`, `postopts`,\n\t\t`allow_cid`, `allow_gid`, `deny_cid`, `deny_gid`, `private`, `pubmail`, `attach`, `bookmark`,`origin`, `moderated`, `file`, `rendered-html`, `rendered-hash`)\n\t\tVALUES( '%s', '%s', %d, '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, '%s', '%s', '%s')", dbesc($datarray['guid']), dbesc($datarray['extid']), intval($datarray['uid']), dbesc($datarray['type']), intval($datarray['wall']), intval($datarray['gravity']), dbesc($datarray['network']), intval($datarray['contact-id']), dbesc($datarray['owner-name']), dbesc($datarray['owner-link']), dbesc($datarray['owner-avatar']), dbesc($datarray['author-name']), dbesc($datarray['author-link']), dbesc($datarray['author-avatar']), dbesc($datarray['created']), dbesc($datarray['edited']), dbesc($datarray['commented']), dbesc($datarray['received']), dbesc($datarray['changed']), dbesc($datarray['uri']), dbesc($datarray['thr-parent']), dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['app']), dbesc($datarray['location']), dbesc($datarray['coord']), dbesc($datarray['tag']), dbesc($datarray['inform']), dbesc($datarray['verb']), dbesc($datarray['object-type']), dbesc($datarray['postopts']), dbesc($datarray['allow_cid']), dbesc($datarray['allow_gid']), dbesc($datarray['deny_cid']), dbesc($datarray['deny_gid']), intval($datarray['private']), intval($datarray['pubmail']), dbesc($datarray['attach']), intval($datarray['bookmark']), intval($datarray['origin']), intval($datarray['moderated']), dbesc($datarray['file']), dbesc($datarray['rendered-html']), dbesc($datarray['rendered-hash'])); $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($datarray['uri'])); if (!count($r)) { logger('mod_item: unable to retrieve post that was just stored.'); notice(t('System error. Post not saved.') . EOL); goaway($a->get_baseurl() . "/" . $return_path); // NOTREACHED } $post_id = $r[0]['id']; logger('mod_item: saved item ' . $post_id); $datarray["id"] = $post_id; $datarray["plink"] = $a->get_baseurl() . '/display/' . urlencode($datarray["guid"]); // update filetags in pconfig file_tag_update_pconfig($uid, $categories_old, $categories_new, 'category'); if ($parent) { // This item is the last leaf and gets the comment box, clear any ancestors $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent` = %d ", dbesc(datetime_convert()), intval($parent)); update_thread($parent, true); // Inherit ACLs from the parent item. $r = q("UPDATE `item` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s', `private` = %d\n\t\t\tWHERE `id` = %d", dbesc($parent_item['allow_cid']), dbesc($parent_item['allow_gid']), dbesc($parent_item['deny_cid']), dbesc($parent_item['deny_gid']), intval($parent_item['private']), intval($post_id)); if ($contact_record != $author) { notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'uid' => $user['uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode($datarray['guid']), 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $parent, 'parent_uri' => $parent_item['uri'])); } // Store the comment signature information in case we need to relay to Diaspora store_diaspora_comment_sig($datarray, $author, $self ? $a->user['prvkey'] : false, $parent_item, $post_id); } else { $parent = $post_id; if ($contact_record != $author) { notification(array('type' => NOTIFY_WALL, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'uid' => $user['uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode($datarray['guid']), 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item')); } } // fallback so that parent always gets set to non-zero. if (!$parent) { $parent = $post_id; } $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s', `plink` = '%s', `changed` = '%s', `last-child` = 1, `visible` = 1\n\t\tWHERE `id` = %d", intval($parent), dbesc($parent == $post_id ? $uri : $parent_item['uri']), dbesc($a->get_baseurl() . '/display/' . urlencode($datarray['guid'])), dbesc(datetime_convert()), intval($post_id)); // photo comments turn the corresponding item visible to the profile wall // This way we don't see every picture in your new photo album posted to your wall at once. // They will show up as people comment on them. if (!$parent_item['visible']) { $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d", intval($parent_item['id'])); update_thread($parent_item['id']); } // update the commented timestamp on the parent q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d", dbesc(datetime_convert()), dbesc(datetime_convert()), intval($parent)); if ($post_id != $parent) { update_thread($parent); } call_hooks('post_local_end', $datarray); if (strlen($emailcc) && $profile_uid == local_user()) { $erecips = explode(',', $emailcc); if (count($erecips)) { foreach ($erecips as $recip) { $addr = trim($recip); if (!strlen($addr)) { continue; } $disclaimer = '<hr />' . sprintf(t('This message was sent to you by %s, a member of the Friendica social network.'), $a->user['username']) . '<br />'; $disclaimer .= sprintf(t('You may visit them online at %s'), $a->get_baseurl() . '/profile/' . $a->user['nickname']) . EOL; $disclaimer .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL; if (!$datarray['title'] == '') { $subject = email_header_encode($datarray['title'], 'UTF-8'); } else { $subject = email_header_encode('[Friendica]' . ' ' . sprintf(t('%s posted an update.'), $a->user['username']), 'UTF-8'); } $link = '<a href="' . $a->get_baseurl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />'; $html = prepare_body($datarray); $message = '<html><body>' . $link . $html . $disclaimer . '</body></html>'; include_once 'include/html2plain.php'; $params = array('fromName' => $a->user['username'], 'fromEmail' => $a->user['email'], 'toEmail' => $addr, 'replyTo' => $a->user['email'], 'messageSubject' => $subject, 'htmlVersion' => $message, 'textVersion' => html2plain($html . $disclaimer)); Emailer::send($params); } } } create_tags_from_item($post_id); create_files_from_item($post_id); if ($post_id == $parent) { add_thread($post_id); } // This is a real juggling act on shared hosting services which kill your processes // e.g. dreamhost. We used to start delivery to our native delivery agents in the background // and then run our plugin delivery from the foreground. We're now doing plugin delivery first, // because as soon as you start loading up a bunch of remote delivey processes, *this* page is // likely to get killed off. If you end up looking at an /item URL and a blank page, // it's very likely the delivery got killed before all your friends could be notified. // Currently the only realistic fixes are to use a reliable server - which precludes shared hosting, // or cut back on plugins which do remote deliveries. proc_run('php', "include/notifier.php", $notify_type, "{$post_id}"); logger('post_complete'); item_post_return($a->get_baseurl(), $api_source, $return_path); // NOTREACHED }
/** * Get data in a form usable by a conversation template * * Returns: * _ The data requested on success * _ false on failure */ public function get_template_data($alike, $dlike, $thread_level = 1) { require_once "mod/proxy.php"; $result = array(); $a = $this->get_app(); $item = $this->get_data(); $edited = false; if (strcmp($item['created'], $item['edited']) != 0) { $edited = array('label' => t('This entry was edited'), 'date' => datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r'), 'relative' => relative_date($item['edited'])); } $commentww = ''; $sparkle = ''; $buttons = ''; $dropping = false; $star = false; $ignore = false; $isstarred = "unstarred"; $indent = ''; $shiny = ''; $osparkle = ''; $total_children = $this->count_descendants(); $conv = $this->get_conversation(); $lock = $item['private'] == 1 || $item['uid'] == local_user() && (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) ? t('Private Message') : false; $shareable = $conv->get_profile_owner() == local_user() && $item['private'] != 1 ? true : false; if (local_user() && link_compare($a->contact['url'], $item['author-link'])) { $edpost = array($a->get_baseurl($ssl_state) . "/editpost/" . $item['id'], t("Edit")); } else { $edpost = false; } if ($this->get_data_value('uid') == local_user() || $this->is_visiting()) { $dropping = true; } $drop = array('dropping' => $dropping, 'pagedrop' => feature_enabled($conv->get_profile_owner(), 'multi_delete') ? $item['pagedrop'] : '', 'select' => t('Select'), 'delete' => t('Delete')); $filer = $conv->get_profile_owner() == local_user() ? t("save to folder") : false; $diff_author = link_compare($item['url'], $item['author-link']) ? false : true; $profile_name = strlen($item['author-name']) && $diff_author ? $item['author-name'] : $item['name']; if ($item['author-link'] && !$item['author-name']) { $profile_name = $item['author-link']; } $sp = false; $profile_link = best_link_url($item, $sp); if ($profile_link === 'mailbox') { $profile_link = ''; } if ($sp) { $sparkle = ' sparkle'; } else { $profile_link = zrl($profile_link); } $normalised = normalise_link(strlen($item['author-link']) ? $item['author-link'] : $item['url']); if ($normalised != 'mailbox' && x($a->contacts, $normalised)) { $profile_avatar = $a->contacts[$normalised]['thumb']; } else { $profile_avatar = strlen($item['author-avatar']) && $diff_author ? $item['author-avatar'] : $a->get_cached_avatar_image($this->get_data_value('thumb')); } $locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => ''); call_hooks('render_location', $locate); $location = strlen($locate['html']) ? $locate['html'] : render_location_google($locate); $searchpath = $a->get_baseurl() . "/search?tag="; $tags = array(); $hashtags = array(); $mentions = array(); /*foreach(explode(',',$item['tag']) as $tag){ $tag = trim($tag); if ($tag!="") { $t = bbcode($tag); $tags[] = $t; if($t[0] == '#') $hashtags[] = $t; elseif($t[0] == '@') $mentions[] = $t; } }*/ $like = x($alike, $item['uri']) ? format_like($alike[$item['uri']], $alike[$item['uri'] . '-l'], 'like', $item['uri']) : ''; $dislike = x($dlike, $item['uri']) ? format_like($dlike[$item['uri']], $dlike[$item['uri'] . '-l'], 'dislike', $item['uri']) : ''; /* * We should avoid doing this all the time, but it depends on the conversation mode * And the conv mode may change when we change the conv, or it changes its mode * Maybe we should establish a way to be notified about conversation changes */ $this->check_wall_to_wall(); if ($this->is_wall_to_wall() && $this->get_owner_url() == $this->get_redirect_url()) { $osparkle = ' sparkle'; } if ($this->is_toplevel()) { if ($conv->get_profile_owner() == local_user()) { $isstarred = $item['starred'] ? "starred" : "unstarred"; $star = array('do' => t("add star"), 'undo' => t("remove star"), 'toggle' => t("toggle star status"), 'classdo' => $item['starred'] ? "hidden" : "", 'classundo' => $item['starred'] ? "" : "hidden", 'starred' => t('starred')); $r = q("SELECT `ignored` FROM `thread` WHERE `uid` = %d AND `iid` = %d LIMIT 1", intval($item['uid']), intval($item['id'])); if (count($r)) { $ignore = array('do' => t("ignore thread"), 'undo' => t("unignore thread"), 'toggle' => t("toggle ignore status"), 'classdo' => $r[0]['ignored'] ? "hidden" : "", 'classundo' => $r[0]['ignored'] ? "" : "hidden", 'ignored' => t('ignored')); } $tagger = ''; if (feature_enabled($conv->get_profile_owner(), 'commtag')) { $tagger = array('add' => t("add tag"), 'class' => ""); } } } else { $indent = 'comment'; } if ($conv->is_writable()) { $buttons = array('like' => array(t("I like this (toggle)"), t("like")), 'dislike' => feature_enabled($conv->get_profile_owner(), 'dislike') ? array(t("I don't like this (toggle)"), t("dislike")) : ''); if ($shareable) { $buttons['share'] = array(t('Share this'), t('share')); } } if (strcmp(datetime_convert('UTC', 'UTC', $item['created']), datetime_convert('UTC', 'UTC', 'now - 12 hours')) > 0) { $shiny = 'shiny'; } localize_item($item); if ($item["postopts"] and !get_config("system", "suppress_language")) { //$langdata = explode(";", $item["postopts"]); //$langstr = substr($langdata[0], 5)." (".round($langdata[1]*100, 1)."%)"; $langstr = ""; if (substr($item["postopts"], 0, 5) == "lang=") { $postopts = substr($item["postopts"], 5); $languages = explode(":", $postopts); if (sizeof($languages) == 1) { $languages = array(); $languages[] = $postopts; } foreach ($languages as $language) { $langdata = explode(";", $language); if ($langstr != "") { $langstr .= ", "; } //$langstr .= $langdata[0]." (".round($langdata[1]*100, 1)."%)"; $langstr .= round($langdata[1] * 100, 1) . "% " . $langdata[0]; } } } $body = prepare_body($item, true); list($categories, $folders) = get_cats_and_terms($item); if ($a->theme['template_engine'] === 'internal') { $body_e = template_escape($body); $text_e = strip_tags(template_escape($body)); $name_e = template_escape($profile_name); $title_e = template_escape($item['title']); $location_e = template_escape($location); $owner_name_e = template_escape($this->get_owner_name()); } else { $body_e = $body; $text_e = strip_tags($body); $name_e = $profile_name; $title_e = $item['title']; $location_e = $location; $owner_name_e = $this->get_owner_name(); } // Disable features that aren't available in several networks if ($item["item_network"] != "dfrn" and isset($buttons["dislike"])) { unset($buttons["dislike"]); $tagger = ''; } if ($item["item_network"] == "feed" and isset($buttons["like"])) { unset($buttons["like"]); } if ($item["item_network"] == "mail" and isset($buttons["like"])) { unset($buttons["like"]); } if ($item["item_network"] == "dspr" and $indent == 'comment' and isset($buttons["like"])) { unset($buttons["like"]); } // Facebook can like comments - but it isn't programmed in the connector yet. if ($item["item_network"] == "face" and $indent == 'comment' and isset($buttons["like"])) { unset($buttons["like"]); } $tmp_item = array('template' => $this->get_template(), 'type' => implode("", array_slice(explode("/", $item['verb']), -1)), 'tags' => $item['tags'], 'hashtags' => $item['hashtags'], 'mentions' => $item['mentions'], 'txt_cats' => t('Categories:'), 'txt_folders' => t('Filed under:'), 'has_cats' => count($categories) ? 'true' : '', 'has_folders' => count($folders) ? 'true' : '', 'categories' => $categories, 'folders' => $folders, 'body' => $body_e, 'text' => $text_e, 'id' => $this->get_id(), 'guid' => $item['guid'], 'linktitle' => sprintf(t('View %s\'s profile @ %s'), $profile_name, strlen($item['author-link']) ? $item['author-link'] : $item['url']), 'olinktitle' => sprintf(t('View %s\'s profile @ %s'), $this->get_owner_name(), strlen($item['owner-link']) ? $item['owner-link'] : $item['url']), 'to' => t('to'), 'via' => t('via'), 'wall' => t('Wall-to-Wall'), 'vwall' => t('via Wall-To-Wall:'), 'profile_url' => $profile_link, 'item_photo_menu' => item_photo_menu($item), 'name' => $name_e, 'thumb' => proxy_url($profile_avatar), 'osparkle' => $osparkle, 'sparkle' => $sparkle, 'title' => $title_e, 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'), 'ago' => $item['app'] ? sprintf(t('%s from %s'), relative_date($item['created']), $item['app']) : relative_date($item['created']), 'app' => $item['app'], 'created' => relative_date($item['created']), 'lock' => $lock, 'location' => $location_e, 'indent' => $indent, 'shiny' => $shiny, 'owner_url' => $this->get_owner_url(), 'owner_photo' => proxy_url($this->get_owner_photo()), 'owner_name' => $owner_name_e, 'plink' => get_plink($item), 'edpost' => feature_enabled($conv->get_profile_owner(), 'edit_posts') ? $edpost : '', 'isstarred' => $isstarred, 'star' => feature_enabled($conv->get_profile_owner(), 'star_posts') ? $star : '', 'ignore' => feature_enabled($conv->get_profile_owner(), 'ignore_posts') ? $ignore : '', 'tagger' => $tagger, 'filer' => feature_enabled($conv->get_profile_owner(), 'filing') ? $filer : '', 'drop' => $drop, 'vote' => $buttons, 'like' => $like, 'dislike' => $dislike, 'switchcomment' => t('Comment'), 'comment' => $this->get_comment_box($indent), 'previewing' => $conv->is_preview() ? ' preview ' : '', 'wait' => t('Please wait'), 'thread_level' => $thread_level, 'postopts' => $langstr, 'edited' => $edited, 'network' => $item["item_network"], 'network_name' => network_to_name($item['item_network'])); $arr = array('item' => $item, 'output' => $tmp_item); call_hooks('display_item', $arr); $result = $arr['output']; $result['children'] = array(); $children = $this->get_children(); $nb_children = count($children); if ($nb_children > 0) { foreach ($children as $child) { $result['children'][] = $child->get_template_data($alike, $dlike, $thread_level + 1); } // Collapse if ($nb_children > 2 || $thread_level > 1) { $result['children'][0]['comment_firstcollapsed'] = true; $result['children'][0]['num_comments'] = sprintf(tt('%d comment', '%d comments', $total_children), $total_children); $result['children'][0]['hidden_comments_num'] = $total_children; $result['children'][0]['hidden_comments_text'] = tt('comment', 'comments', $total_children); $result['children'][0]['hide_text'] = t('show more'); if ($thread_level > 1) { $result['children'][$nb_children - 1]['comment_lastcollapsed'] = true; } else { $result['children'][$nb_children - 3]['comment_lastcollapsed'] = true; } } } if ($this->is_toplevel()) { $result['total_comments_num'] = "{$total_children}"; $result['total_comments_text'] = tt('comment', 'comments', $total_children); } $result['private'] = $item['private']; $result['toplevel'] = $this->is_toplevel() ? 'toplevel_item' : ''; if ($this->is_threaded()) { $result['flatten'] = false; $result['threaded'] = true; } else { $result['flatten'] = true; $result['threaded'] = false; } return $result; }
function delivery_run($argv, $argc) { global $a, $db; if (is_null($a)) { $a = new App(); } if (is_null($db)) { @(include ".htconfig.php"); require_once "dba.php"; $db = new dba($db_host, $db_user, $db_pass, $db_data); unset($db_host, $db_user, $db_pass, $db_data); } require_once "session.php"; require_once "datetime.php"; require_once 'include/items.php'; require_once 'include/bbcode.php'; require_once 'include/diaspora.php'; require_once 'include/email.php'; load_config('config'); load_config('system'); load_hooks(); if ($argc < 3) { return; } $a->set_baseurl(get_config('system', 'url')); logger('delivery: invoked: ' . print_r($argv, true), LOGGER_DEBUG); $cmd = $argv[1]; $item_id = intval($argv[2]); $contact_id = intval($argv[3]); // Some other process may have delivered this item already. $r = q("select * from deliverq where cmd = '%s' and item = %d and contact = %d limit 1", dbesc($cmd), dbesc($item_id), dbesc($contact_id)); if (!count($r)) { return; } // It's ours to deliver. Remove it from the queue. q("delete from deliverq where cmd = '%s' and item = %d and contact = %d limit 1", dbesc($cmd), dbesc($item_id), dbesc($contact_id)); if (!$item_id || !$contact_id) { return; } $expire = false; $top_level = false; $recipients = array(); $url_recipients = array(); $normal_mode = true; $recipients[] = $contact_id; if ($cmd === 'expire') { $normal_mode = false; $expire = true; $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1 \n\t\t\tAND `deleted` = 1 AND `changed` > UTC_TIMESTAMP() - INTERVAL 30 MINUTE", intval($item_id)); $uid = $item_id; $item_id = 0; if (!count($items)) { return; } } else { // find ancestors $r = q("SELECT * FROM `item` WHERE `id` = %d and visible = 1 and moderated = 0 LIMIT 1", intval($item_id)); if (!count($r) || !intval($r[0]['parent'])) { return; } $target_item = $r[0]; $parent_id = intval($r[0]['parent']); $uid = $r[0]['uid']; $updated = $r[0]['edited']; if (!$parent_id) { return; } $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer` \n\t\t\tFROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d and visible = 1 and moderated = 0 ORDER BY `id` ASC", intval($parent_id)); if (!count($items)) { return; } $icontacts = null; $contacts_arr = array(); foreach ($items as $item) { if (!in_array($item['contact-id'], $contacts_arr)) { $contacts_arr[] = intval($item['contact-id']); } } if (count($contacts_arr)) { $str_contacts = implode(',', $contacts_arr); $icontacts = q("SELECT * FROM `contact` \n\t\t\t\tWHERE `id` IN ( {$str_contacts} ) "); } if (!($icontacts && count($icontacts))) { return; } // avoid race condition with deleting entries if ($items[0]['deleted']) { foreach ($items as $item) { $item['deleted'] = 1; } } if (count($items) == 1 && $items[0]['uri'] === $items[0]['parent-uri']) { logger('delivery: top level post'); $top_level = true; } } $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`, \n\t\t`user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`, \n\t\t`user`.`page-flags`, `user`.`prvnets`\n\t\tFROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid` \n\t\tWHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1", intval($uid)); if (!count($r)) { return; } $owner = $r[0]; $walltowall = $top_level && $owner['id'] != $items[0]['contact-id'] ? true : false; $public_message = true; // fill this in with a single salmon slap if applicable $slap = ''; require_once 'include/group.php'; $parent = $items[0]; // This is IMPORTANT!!!! // We will only send a "notify owner to relay" or followup message if the referenced post // originated on our system by virtue of having our hostname somewhere // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere. // if $parent['wall'] == 1 we will already have the parent message in our array // and we will relay the whole lot. // expire sends an entire group of expire messages and cannot be forwarded. // However the conversation owner will be a part of the conversation and will // be notified during this run. // Other DFRN conversation members will be alerted during polled updates. // Diaspora members currently are not notified of expirations, and other networks have // either limited or no ability to process deletions. We should at least fix Diaspora // by stringing togther an array of retractions and sending them onward. $localhost = $a->get_hostname(); if (strpos($localhost, ':')) { $localhost = substr($localhost, 0, strpos($localhost, ':')); } /** * * Be VERY CAREFUL if you make any changes to the following line. Seemingly innocuous changes * have been known to cause runaway conditions which affected several servers, along with * permissions issues. * */ if (!$top_level && $parent['wall'] == 0 && !$expire && stristr($target_item['uri'], $localhost)) { logger('relay denied for delivery agent.'); /* no relay allowed for direct contact delivery */ return; } if (strlen($parent['allow_cid']) || strlen($parent['allow_gid']) || strlen($parent['deny_cid']) || strlen($parent['deny_gid'])) { $public_message = false; // private recipients, not public } $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `blocked` = 0 AND `pending` = 0", intval($contact_id)); if (count($r)) { $contact = $r[0]; } $hubxml = feed_hublinks(); logger('notifier: slaps: ' . print_r($slaps, true), LOGGER_DATA); require_once 'include/salmon.php'; if ($contact['self']) { return; } $deliver_status = 0; switch ($contact['network']) { case NETWORK_DFRN: logger('notifier: dfrndelivery: ' . $contact['name']); $feed_template = get_markup_template('atom_feed.tpl'); $mail_template = get_markup_template('atom_mail.tpl'); $atom = ''; $birthday = feed_birthday($owner['uid'], $owner['timezone']); if (strlen($birthday)) { $birthday = '<dfrn:birthday>' . xmlify($birthday) . '</dfrn:birthday>'; } $atom .= replace_macros($feed_template, array('$version' => xmlify(FRIENDICA_VERSION), '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner['nickname']), '$feed_title' => xmlify($owner['name']), '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', $updated . '+00:00', ATOM_TIME)), '$hub' => $hubxml, '$salmon' => '', '$name' => xmlify($owner['name']), '$profile_page' => xmlify($owner['url']), '$photo' => xmlify($owner['photo']), '$thumb' => xmlify($owner['thumb']), '$picdate' => xmlify(datetime_convert('UTC', 'UTC', $owner['avatar-date'] . '+00:00', ATOM_TIME)), '$uridate' => xmlify(datetime_convert('UTC', 'UTC', $owner['uri-date'] . '+00:00', ATOM_TIME)), '$namdate' => xmlify(datetime_convert('UTC', 'UTC', $owner['name-date'] . '+00:00', ATOM_TIME)), '$birthday' => $birthday)); foreach ($items as $item) { if (!$item['parent']) { continue; } // private emails may be in included in public conversations. Filter them. if ($public_message && $item['private']) { continue; } $item_contact = get_item_contact($item, $icontacts); if (!$item_contact) { continue; } if ($normal_mode) { if ($item_id == $item['id'] || $item['id'] == $item['parent']) { $atom .= atom_entry($item, 'text', $item_contact, $owner, true); } } else { $atom .= atom_entry($item, 'text', $item_contact, $owner, true); } } $atom .= '</feed>' . "\r\n"; logger('notifier: ' . $atom, LOGGER_DATA); $basepath = implode('/', array_slice(explode('/', $contact['url']), 0, 3)); // perform local delivery if we are on the same site if (link_compare($basepath, $a->get_baseurl())) { $nickname = basename($contact['url']); if ($contact['issued-id']) { $sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id'])); } else { $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id'])); } $x = q("SELECT\t`contact`.*, `contact`.`uid` AS `importer_uid`, \n\t\t\t\t\t`contact`.`pubkey` AS `cpubkey`, \n\t\t\t\t\t`contact`.`prvkey` AS `cprvkey`, \n\t\t\t\t\t`contact`.`thumb` AS `thumb`, \n\t\t\t\t\t`contact`.`url` as `url`,\n\t\t\t\t\t`contact`.`name` as `senderName`,\n\t\t\t\t\t`user`.* \n\t\t\t\t\tFROM `contact` \n\t\t\t\t\tLEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` \n\t\t\t\t\tWHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0\n\t\t\t\t\tAND `contact`.`network` = '%s' AND `user`.`nickname` = '%s'\n\t\t\t\t\t{$sql_extra}\n\t\t\t\t\tAND `user`.`account_expired` = 0 LIMIT 1", dbesc(NETWORK_DFRN), dbesc($nickname)); if (count($x)) { require_once 'library/simplepie/simplepie.inc'; logger('mod-delivery: local delivery'); local_delivery($x[0], $atom); break; } } $deliver_status = dfrn_deliver($owner, $contact, $atom); logger('notifier: dfrn_delivery returns ' . $deliver_status); if ($deliver_status == -1) { logger('notifier: delivery failed: queuing message'); add_to_queue($contact['id'], NETWORK_DFRN, $atom); } break; case NETWORK_OSTATUS: // Do not send to otatus if we are not configured to send to public networks if ($owner['prvnets']) { break; } if (get_config('system', 'ostatus_disabled') || get_config('system', 'dfrn_only')) { break; } // only send salmon if public - e.g. if it's ok to notify // a public hub, it's ok to send a salmon if ($public_message && !$expire) { $slaps = array(); foreach ($items as $item) { if (!$item['parent']) { continue; } // private emails may be in included in public conversations. Filter them. if ($public_message && $item['private']) { continue; } $item_contact = get_item_contact($item, $icontacts); if (!$item_contact) { continue; } if ($top_level && $public_message && $item['author-link'] === $item['owner-link'] && !$expire) { $slaps[] = atom_entry($item, 'html', $item_contact, $owner, true); } } logger('notifier: slapdelivery: ' . $contact['name']); foreach ($slaps as $slappy) { if ($contact['notify']) { $deliver_status = slapper($owner, $contact['notify'], $slappy); if ($deliver_status == -1) { // queue message for redelivery add_to_queue($contact['id'], NETWORK_OSTATUS, $slappy); } } } } break; case NETWORK_MAIL: case NETWORK_MAIL2: if (get_config('system', 'dfrn_only')) { break; } // WARNING: does not currently convert to RFC2047 header encodings, etc. $addr = $contact['addr']; if (!strlen($addr)) { break; } if ($cmd === 'wall-new' || $cmd === 'comment-new') { $it = null; if ($cmd === 'wall-new') { $it = $items[0]; } else { $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($argv[2]), intval($uid)); if (count($r)) { $it = $r[0]; } } if (!$it) { break; } $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($uid)); if (!count($local_user)) { break; } $reply_to = ''; $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1", intval($uid)); if ($r1 && $r1[0]['reply_to']) { $reply_to = $r1[0]['reply_to']; } $subject = $it['title'] ? email_header_encode($it['title'], 'UTF-8') : t("(no subject)"); // only expose our real email address to true friends if ($contact['rel'] == CONTACT_IS_FRIEND && !$contact['blocked']) { $headers = 'From: ' . email_header_encode($local_user[0]['username'], 'UTF-8') . ' <' . $local_user[0]['email'] . '>' . "\n"; } else { $headers = 'From: ' . email_header_encode($local_user[0]['username'], 'UTF-8') . ' <' . t('noreply') . '@' . $a->get_hostname() . '>' . "\n"; } if ($reply_to) { $headers .= 'Reply-to: ' . $reply_to . "\n"; } $headers .= 'Message-id: <' . $it['uri'] . '>' . "\n"; if ($it['uri'] !== $it['parent-uri']) { $header .= 'References: <' . $it['parent-uri'] . '>' . "\n"; if (!strlen($it['title'])) { $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' LIMIT 1", dbesc($it['parent-uri'])); if (count($r)) { $subtitle = $r[0]['title']; if ($subtitle) { if (strncasecmp($subtitle, 'RE:', 3)) { $subject = $subtitle; } else { $subject = 'Re: ' . $subtitle; } } } } } $headers .= 'MIME-Version: 1.0' . "\n"; $headers .= 'Content-Type: text/html; charset=UTF-8' . "\n"; $headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n"; $html = prepare_body($it); $message = '<html><body>' . $html . '</body></html>'; logger('notifier: email delivery to ' . $addr); mail($addr, $subject, $message, $headers); } break; case NETWORK_DIASPORA: if ($public_message) { $loc = 'public batch ' . $contact['batch']; } else { $loc = $contact['name']; } logger('delivery: diaspora batch deliver: ' . $loc); if (get_config('system', 'dfrn_only') || !get_config('system', 'diaspora_enabled') || !$normal_mode) { break; } if (!$contact['pubkey'] && !$public_message) { break; } if ($target_item['verb'] === ACTIVITY_DISLIKE) { // unsupported break; } elseif ($target_item['deleted'] && $target_item['verb'] !== ACTIVITY_LIKE) { logger('delivery: diaspora retract: ' . $loc); // diaspora delete, diaspora_send_retraction($target_item, $owner, $contact, $public_message); break; } elseif ($target_item['parent'] != $target_item['id']) { logger('delivery: diaspora relay: ' . $loc); // we are the relay - send comments, likes and unlikes to our conversants diaspora_send_relay($target_item, $owner, $contact, $public_message); break; } elseif ($top_level && !$walltowall) { // currently no workable solution for sending walltowall logger('delivery: diaspora status: ' . $loc); diaspora_send_status($target_item, $owner, $contact, $public_message); break; } logger('delivery: diaspora unknown mode: ' . $contact['name']); break; case NETWORK_FEED: case NETWORK_FACEBOOK: if (get_config('system', 'dfrn_only')) { break; } default: break; } return; }
function item_post(&$a) { if (!local_user() && !remote_user()) { return; } require_once 'include/security.php'; $uid = local_user(); if (x($_POST, 'dropitems')) { require_once 'include/items.php'; $arr_drop = explode(',', $_POST['dropitems']); drop_items($arr_drop); $json = array('success' => 1); echo json_encode($json); killme(); } call_hooks('post_local_start', $_POST); $api_source = x($_POST, 'api_source') && $_POST['api_source'] ? true : false; $return_path = x($_POST, 'return') ? $_POST['return'] : ''; /** * Is this a reply to something? */ $parent = x($_POST, 'parent') ? intval($_POST['parent']) : 0; $parent_uri = x($_POST, 'parent_uri') ? trim($_POST['parent_uri']) : ''; $parent_item = null; $parent_contact = null; $thr_parent = ''; $parid = 0; $r = false; $preview = x($_POST, 'preview') ? intval($_POST['preview']) : 0; if ($parent || $parent_uri) { if (!x($_POST, 'type')) { $_POST['type'] = 'net-comment'; } if ($parent) { $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($parent)); } elseif ($parent_uri && local_user()) { // This is coming from an API source, and we are logged in $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($parent_uri), intval(local_user())); } // if this isn't the real parent of the conversation, find it if ($r !== false && count($r)) { $parid = $r[0]['parent']; if ($r[0]['id'] != $r[0]['parent']) { $r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1", intval($parid)); } } if ($r === false || !count($r)) { notice(t('Unable to locate original post.') . EOL); if (x($_POST, 'return')) { goaway($a->get_baseurl() . "/" . $return_path); } killme(); } $parent_item = $r[0]; $parent = $r[0]['id']; // multi-level threading - preserve the info but re-parent to our single level threading if ($parid && $parid != $parent) { $thr_parent = $parent_uri; } if ($parent_item['contact-id'] && $uid) { $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($parent_item['contact-id']), intval($uid)); if (count($r)) { $parent_contact = $r[0]; } } } if ($parent) { logger('mod_post: parent=' . $parent); } $profile_uid = x($_POST, 'profile_uid') ? intval($_POST['profile_uid']) : 0; $post_id = x($_POST['post_id']) ? intval($_POST['post_id']) : 0; $app = x($_POST['source']) ? strip_tags($_POST['source']) : ''; if (!can_write_wall($a, $profile_uid)) { notice(t('Permission denied.') . EOL); if (x($_POST, 'return')) { goaway($a->get_baseurl() . "/" . $return_path); } killme(); } // is this an edited post? $orig_post = null; if ($post_id) { $i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($post_id)); if (!count($i)) { killme(); } $orig_post = $i[0]; } $user = null; $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($profile_uid)); if (count($r)) { $user = $r[0]; } if ($orig_post) { $str_group_allow = $orig_post['allow_gid']; $str_contact_allow = $orig_post['allow_cid']; $str_group_deny = $orig_post['deny_gid']; $str_contact_deny = $orig_post['deny_cid']; $title = $orig_post['title']; $location = $orig_post['location']; $coord = $orig_post['coord']; $verb = $orig_post['verb']; $emailcc = $orig_post['emailcc']; $app = $orig_post['app']; $body = escape_tags(trim($_POST['body'])); $private = $orig_post['private']; $pubmail_enable = $orig_post['pubmail']; } else { $str_group_allow = perms2str($_POST['group_allow']); $str_contact_allow = perms2str($_POST['contact_allow']); $str_group_deny = perms2str($_POST['group_deny']); $str_contact_deny = perms2str($_POST['contact_deny']); $title = notags(trim($_POST['title'])); $location = notags(trim($_POST['location'])); $coord = notags(trim($_POST['coord'])); $verb = notags(trim($_POST['verb'])); $emailcc = notags(trim($_POST['emailcc'])); $body = escape_tags(trim($_POST['body'])); $private = strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny) ? 1 : 0; if ($parent_item && ($parent_item['private'] || strlen($parent_item['allow_cid']) || strlen($parent_item['allow_gid']) || strlen($parent_item['deny_cid']) || strlen($parent_item['deny_gid']))) { $private = 1; } $pubmail_enable = x($_POST, 'pubmail_enable') && intval($_POST['pubmail_enable']) && !$private ? 1 : 0; // if using the API, we won't see pubmail_enable - figure out if it should be set if ($api_source && $profile_uid && $profile_uid == local_user() && !$private) { $mail_disabled = function_exists('imap_open') && !get_config('system', 'imap_disabled') ? 0 : 1; if (!$mail_disabled) { $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1", intval(local_user())); if (count($r) && intval($r[0]['pubmail'])) { $pubmail_enabled = true; } } } if (!strlen($body)) { info(t('Empty post discarded.') . EOL); if (x($_POST, 'return')) { goaway($a->get_baseurl() . "/" . $return_path); } killme(); } } if ($api_source && !array_key_exists('allow_cid', $_REQUEST) && !array_key_exists('allow_gid', $_REQUEST) && !array_key_exists('deny_cid', $_REQUEST) && !array_key_exists('deny_gid', $_REQUEST)) { $str_group_allow = $user['allow_gid']; $str_contact_allow = $user['allow_cid']; $str_group_deny = $user['deny_gid']; $str_contact_deny = $user['deny_cid']; } // get contact info for poster $author = null; $self = false; if ($_SESSION['uid'] && $_SESSION['uid'] == $profile_uid) { $self = true; $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($_SESSION['uid'])); } else { if (x($_SESSION, 'visitor_id') && intval($_SESSION['visitor_id'])) { $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($_SESSION['visitor_id'])); } } if (count($r)) { $author = $r[0]; $contact_id = $author['id']; } // get contact info for owner if ($profile_uid == $_SESSION['uid']) { $contact_record = $author; } else { $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($profile_uid)); if (count($r)) { $contact_record = $r[0]; } } $post_type = notags(trim($_POST['type'])); if ($post_type === 'net-comment') { if ($parent_item !== null) { if ($parent_item['wall'] == 1) { $post_type = 'wall-comment'; } else { $post_type = 'remote-comment'; } } } /** * * When a photo was uploaded into the message using the (profile wall) ajax * uploader, The permissions are initially set to disallow anybody but the * owner from seeing it. This is because the permissions may not yet have been * set for the post. If it's private, the photo permissions should be set * appropriately. But we didn't know the final permissions on the post until * now. So now we'll look for links of uploaded messages that are in the * post and set them to the same permissions as the post itself. * */ $match = null; if (!$preview && preg_match_all("/\\[img\\](.*?)\\[\\/img\\]/", $body, $match)) { $images = $match[1]; if (count($images)) { foreach ($images as $image) { if (!stristr($image, $a->get_baseurl() . '/photo/')) { continue; } $image_uri = substr($image, strrpos($image, '/') + 1); $image_uri = substr($image_uri, 0, strpos($image_uri, '-')); if (!strlen($image_uri)) { continue; } $srch = '<' . intval($profile_uid) . '>'; $r = q("SELECT `id` FROM `photo` WHERE `allow_cid` = '%s' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = ''\n\t\t\t\t\tAND `resource-id` = '%s' AND `uid` = %d LIMIT 1", dbesc($srch), dbesc($image_uri), intval($profile_uid)); if (!count($r)) { continue; } $r = q("UPDATE `photo` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\tWHERE `resource-id` = '%s' AND `uid` = %d AND `album` = '%s' ", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), dbesc($image_uri), intval($profile_uid), dbesc(t('Wall Photos'))); } } } /** * Next link in any attachment references we find in the post. */ $match = false; if (!$preview && preg_match_all("/\\[attachment\\](.*?)\\[\\/attachment\\]/", $body, $match)) { $attaches = $match[1]; if (count($attaches)) { foreach ($attaches as $attach) { $r = q("SELECT * FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($attach)); if (count($r)) { $r = q("UPDATE `attach` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\t\tWHERE `uid` = %d AND `id` = %d LIMIT 1", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), intval($profile_uid), intval($attach)); } } } } // embedded bookmark in post? set bookmark flag $bookmark = 0; if (preg_match_all("/\\[bookmark\\=([^\\]]*)\\](.*?)\\[\\/bookmark\\]/ism", $body, $match, PREG_SET_ORDER)) { $bookmark = 1; } $body = bb_translate_video($body); /** * Fold multi-line [code] sequences */ $body = preg_replace('/\\[\\/code\\]\\s*\\[code\\]/ism', "\n", $body); /** * Look for any tags and linkify them */ $str_tags = ''; $inform = ''; $tags = get_tags($body); /** * add a statusnet style reply tag if the original post was from there * and we are replying, and there isn't one already */ if ($parent_contact && $parent_contact['network'] === NETWORK_OSTATUS && $parent_contact['nick'] && !in_array('@' . $parent_contact['nick'], $tags)) { $body = '@' . $parent_contact['nick'] . ' ' . $body; $tags[] = '@' . $parent_contact['nick']; } if (count($tags)) { foreach ($tags as $tag) { if (isset($profile)) { unset($profile); } if (strpos($tag, '#') === 0) { if (strpos($tag, '[url=')) { continue; } $basetag = str_replace('_', ' ', substr($tag, 1)); $body = str_replace($tag, '#[url=' . $a->get_baseurl() . '/search?search=' . rawurlencode($basetag) . ']' . $basetag . '[/url]', $body); $newtag = '#[url=' . $a->get_baseurl() . '/search?search=' . rawurlencode($basetag) . ']' . $basetag . '[/url]'; if (!stristr($str_tags, $newtag)) { if (strlen($str_tags)) { $str_tags .= ','; } $str_tags .= $newtag; } continue; } if (strpos($tag, '@') === 0) { if (strpos($tag, '[url=')) { continue; } $stat = false; $name = substr($tag, 1); if (strpos($name, '@') || strpos($name, 'http://')) { $newname = $name; $links = @lrdd($name); if (count($links)) { foreach ($links as $link) { if ($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') { $profile = $link['@attributes']['href']; } if ($link['@attributes']['rel'] === 'salmon') { if (strlen($inform)) { $inform .= ','; } $inform .= 'url:' . str_replace(',', '%2c', $link['@attributes']['href']); } } } } else { $newname = $name; $alias = ''; $tagcid = 0; if (strrpos($newname, '+')) { $tagcid = intval(substr($newname, strrpos($newname, '+') + 1)); if (strpos($name, ' ')) { $name = substr($name, 0, strpos($name, ' ')); } } if ($tagcid) { $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($tagcid), intval($profile_uid)); } elseif (strstr($name, '_') || strstr($name, ' ')) { $newname = str_replace('_', ' ', $name); $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1", dbesc($newname), intval($profile_uid)); } else { $r = q("SELECT * FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1", dbesc($name), dbesc($name), intval($profile_uid)); } if (count($r)) { $profile = $r[0]['url']; if ($r[0]['network'] === 'stat') { $newname = $r[0]['nick']; $stat = true; if ($r[0]['alias']) { $alias = $r[0]['alias']; } } else { $newname = $r[0]['name']; } if (strlen($inform)) { $inform .= ','; } $inform .= 'cid:' . $r[0]['id']; } } if ($profile) { $body = str_replace('@' . $name, '@' . '[url=' . $profile . ']' . $newname . '[/url]', $body); $profile = str_replace(',', '%2c', $profile); $newtag = '@[url=' . $profile . ']' . $newname . '[/url]'; if (!stristr($str_tags, $newtag)) { if (strlen($str_tags)) { $str_tags .= ','; } $str_tags .= $newtag; } // Status.Net seems to require the numeric ID URL in a mention if the person isn't // subscribed to you. But the nickname URL is OK if they are. Grrr. We'll tag both. if (strlen($alias)) { $newtag = '@[url=' . $alias . ']' . $newname . '[/url]'; if (!stristr($str_tags, $newtag)) { if (strlen($str_tags)) { $str_tags .= ','; } $str_tags .= $newtag; } } } } } } $attachments = ''; $match = false; if (preg_match_all('/(\\[attachment\\]([0-9]+)\\[\\/attachment\\])/', $body, $match)) { foreach ($match[2] as $mtch) { $r = q("SELECT `id`,`filename`,`filesize`,`filetype` FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($mtch)); if (count($r)) { if (strlen($attachments)) { $attachments .= ','; } $attachments .= '[attach]href="' . $a->get_baseurl() . '/attach/' . $r[0]['id'] . '" length="' . $r[0]['filesize'] . '" type="' . $r[0]['filetype'] . '" title="' . ($r[0]['filename'] ? $r[0]['filename'] : '') . '"[/attach]'; } $body = str_replace($match[1], '', $body); } } $wall = 0; if ($post_type === 'wall' || $post_type === 'wall-comment') { $wall = 1; } if (!strlen($verb)) { $verb = ACTIVITY_POST; } $gravity = $parent ? 6 : 0; // even if the post arrived via API we are considering that it // originated on this site by default for determining relayability. $origin = x($_REQUEST, 'origin') ? intval($_REQUEST['origin']) : 1; $notify_type = $parent ? 'comment-new' : 'wall-new'; $uri = item_new_uri($a->get_hostname(), $profile_uid); $datarray = array(); $datarray['uid'] = $profile_uid; $datarray['type'] = $post_type; $datarray['wall'] = $wall; $datarray['gravity'] = $gravity; $datarray['contact-id'] = $contact_id; $datarray['owner-name'] = $contact_record['name']; $datarray['owner-link'] = $contact_record['url']; $datarray['owner-avatar'] = $contact_record['thumb']; $datarray['author-name'] = $author['name']; $datarray['author-link'] = $author['url']; $datarray['author-avatar'] = $author['thumb']; $datarray['created'] = datetime_convert(); $datarray['edited'] = datetime_convert(); $datarray['commented'] = datetime_convert(); $datarray['received'] = datetime_convert(); $datarray['changed'] = datetime_convert(); $datarray['uri'] = $uri; $datarray['title'] = $title; $datarray['body'] = $body; $datarray['app'] = $app; $datarray['location'] = $location; $datarray['coord'] = $coord; $datarray['tag'] = $str_tags; $datarray['inform'] = $inform; $datarray['verb'] = $verb; $datarray['allow_cid'] = $str_contact_allow; $datarray['allow_gid'] = $str_group_allow; $datarray['deny_cid'] = $str_contact_deny; $datarray['deny_gid'] = $str_group_deny; $datarray['private'] = $private; $datarray['pubmail'] = $pubmail_enable; $datarray['attach'] = $attachments; $datarray['bookmark'] = intval($bookmark); $datarray['thr-parent'] = $thr_parent; $datarray['postopts'] = ''; $datarray['origin'] = $origin; /** * These fields are for the convenience of plugins... * 'self' if true indicates the owner is posting on their own wall * If parent is 0 it is a top-level post. */ $datarray['parent'] = $parent; $datarray['self'] = $self; // $datarray['prvnets'] = $user['prvnets']; if ($orig_post) { $datarray['edit'] = true; } else { $datarray['guid'] = get_guid(); } // preview mode - prepare the body for display and send it via json if ($preview) { require_once 'include/conversation.php'; $o = conversation(&$a, array(array_merge($contact_record, $datarray)), 'search', false, true); echo json_encode(array('preview' => $o)); killme(); } call_hooks('post_local', $datarray); if ($orig_post) { $r = q("UPDATE `item` SET `body` = '%s', `edited` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1", dbesc($body), dbesc(datetime_convert()), intval($post_id), intval($profile_uid)); proc_run('php', "include/notifier.php", 'edit_post', "{$post_id}"); if (x($_POST, 'return') && strlen($return_path)) { logger('return: ' . $return_path); goaway($a->get_baseurl() . "/" . $return_path); } killme(); } else { $post_id = 0; } $r = q("INSERT INTO `item` (`guid`, `uid`,`type`,`wall`,`gravity`,`contact-id`,`owner-name`,`owner-link`,`owner-avatar`, \n\t\t`author-name`, `author-link`, `author-avatar`, `created`, `edited`, `commented`, `received`, `changed`, `uri`, `thr-parent`, `title`, `body`, `app`, `location`, `coord`, \n\t\t`tag`, `inform`, `verb`, `postopts`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid`, `private`, `pubmail`, `attach`, `bookmark`,`origin` )\n\t\tVALUES( '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d )", dbesc($datarray['guid']), intval($datarray['uid']), dbesc($datarray['type']), intval($datarray['wall']), intval($datarray['gravity']), intval($datarray['contact-id']), dbesc($datarray['owner-name']), dbesc($datarray['owner-link']), dbesc($datarray['owner-avatar']), dbesc($datarray['author-name']), dbesc($datarray['author-link']), dbesc($datarray['author-avatar']), dbesc($datarray['created']), dbesc($datarray['edited']), dbesc($datarray['commented']), dbesc($datarray['received']), dbesc($datarray['changed']), dbesc($datarray['uri']), dbesc($datarray['thr-parent']), dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['app']), dbesc($datarray['location']), dbesc($datarray['coord']), dbesc($datarray['tag']), dbesc($datarray['inform']), dbesc($datarray['verb']), dbesc($datarray['postopts']), dbesc($datarray['allow_cid']), dbesc($datarray['allow_gid']), dbesc($datarray['deny_cid']), dbesc($datarray['deny_gid']), intval($datarray['private']), intval($datarray['pubmail']), dbesc($datarray['attach']), intval($datarray['bookmark']), intval($datarray['origin'])); $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($datarray['uri'])); if (count($r)) { $post_id = $r[0]['id']; logger('mod_item: saved item ' . $post_id); if ($parent) { // This item is the last leaf and gets the comment box, clear any ancestors $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent` = %d ", dbesc(datetime_convert()), intval($parent)); // Inherit ACL's from the parent item. $r = q("UPDATE `item` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s', `private` = %d\n\t\t\t\tWHERE `id` = %d LIMIT 1", dbesc($parent_item['allow_cid']), dbesc($parent_item['allow_gid']), dbesc($parent_item['deny_cid']), dbesc($parent_item['deny_gid']), intval($parent_item['private']), intval($post_id)); if ($contact_record != $author) { notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id, 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item')); } // We won't be able to sign Diaspora comments for authenticated visitors - we don't have their private key if ($self) { require_once 'include/bb2diaspora.php'; $signed_body = html_entity_decode(bb2diaspora($datarray['body'])); $myaddr = $a->user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(), '://') + 3); if ($datarray['verb'] === ACTIVITY_LIKE) { $signed_text = $datarray['guid'] . ';' . 'Post' . ';' . $parent_item['guid'] . ';' . 'true' . ';' . $myaddr; } else { $signed_text = $datarray['guid'] . ';' . $parent_item['guid'] . ';' . $signed_body . ';' . $myaddr; } $authorsig = base64_encode(rsa_sign($signed_text, $a->user['prvkey'], 'sha256')); q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($post_id), dbesc($signed_text), dbesc(base64_encode($authorsig)), dbesc($myaddr)); } } else { $parent = $post_id; if ($contact_record != $author) { notification(array('type' => NOTIFY_WALL, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id, 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item')); } } // fallback so that parent always gets set to non-zero. if (!$parent) { $parent = $post_id; } $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s', `plink` = '%s', `changed` = '%s', `last-child` = 1, `visible` = 1\n\t\t\tWHERE `id` = %d LIMIT 1", intval($parent), dbesc($parent == $post_id ? $uri : $parent_item['uri']), dbesc($a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id), dbesc(datetime_convert()), intval($post_id)); // photo comments turn the corresponding item visible to the profile wall // This way we don't see every picture in your new photo album posted to your wall at once. // They will show up as people comment on them. if (!$parent_item['visible']) { $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d LIMIT 1", intval($parent_item['id'])); } } else { logger('mod_item: unable to retrieve post that was just stored.'); notify(t('System error. Post not saved.')); goaway($a->get_baseurl() . "/" . $return_path); // NOTREACHED } // update the commented timestamp on the parent q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d LIMIT 1", dbesc(datetime_convert()), dbesc(datetime_convert()), intval($parent)); $datarray['id'] = $post_id; $datarray['plink'] = $a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id; call_hooks('post_local_end', $datarray); if (strlen($emailcc) && $profile_uid == local_user()) { $erecips = explode(',', $emailcc); if (count($erecips)) { foreach ($erecips as $recip) { $addr = trim($recip); if (!strlen($addr)) { continue; } $disclaimer = '<hr />' . sprintf(t('This message was sent to you by %s, a member of the Friendica social network.'), $a->user['username']) . '<br />'; $disclaimer .= sprintf(t('You may visit them online at %s'), $a->get_baseurl() . '/profile/' . $a->user['nickname']) . EOL; $disclaimer .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL; $subject = '[Friendica]' . ' ' . sprintf(t('%s posted an update.'), $a->user['username']); $headers = 'From: ' . $a->user['username'] . ' <' . $a->user['email'] . '>' . "\n"; $headers .= 'MIME-Version: 1.0' . "\n"; $headers .= 'Content-Type: text/html; charset=UTF-8' . "\n"; $headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n"; $link = '<a href="' . $a->get_baseurl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />'; $html = prepare_body($datarray); $message = '<html><body>' . $link . $html . $disclaimer . '</body></html>'; @mail($addr, $subject, $message, $headers); } } } // This is a real juggling act on shared hosting services which kill your processes // e.g. dreamhost. We used to start delivery to our native delivery agents in the background // and then run our plugin delivery from the foreground. We're now doing plugin delivery first, // because as soon as you start loading up a bunch of remote delivey processes, *this* page is // likely to get killed off. If you end up looking at an /item URL and a blank page, // it's very likely the delivery got killed before all your friends could be notified. // Currently the only realistic fixes are to use a reliable server - which precludes shared hosting, // or cut back on plugins which do remote deliveries. proc_run('php', "include/notifier.php", $notify_type, "{$post_id}"); logger('post_complete'); // figure out how to return, depending on from whence we came if ($api_source) { return; } if ($return_path) { goaway($a->get_baseurl() . "/" . $return_path); } $json = array('success' => 1); if (x($_POST, 'jsreload') && strlen($_POST['jsreload'])) { $json['reload'] = $a->get_baseurl() . '/' . $_POST['jsreload']; } logger('post_json: ' . print_r($json, true), LOGGER_DEBUG); echo json_encode($json); killme(); // NOTREACHED }
/** * Get data in a form usable by a conversation template * * Returns: * _ The data requested on success * _ false on failure */ public function get_template_data($alike, $dlike, $thread_level = 1) { $t1 = dba_timer(); $result = array(); $a = $this->get_app(); $item = $this->get_data(); $commentww = ''; $sparkle = ''; $buttons = ''; $dropping = false; $star = false; $isstarred = "unstarred icon-star-empty"; $indent = ''; $osparkle = ''; $total_children = $this->count_descendants(); $conv = $this->get_conversation(); $observer = $conv->get_observer(); $lock = $item['item_private'] == 1 || $item['uid'] == local_user() && (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) ? t('Private Message') : false; $shareable = $conv->get_profile_owner() == local_user() && $item['item_private'] != 1 ? true : false; // allow an exemption for sharing stuff from your private feeds if ($item['author']['xchan_network'] === 'rss') { $shareable = true; } $mode = $conv->get_mode(); if (local_user() && $observer['xchan_hash'] === $item['author_xchan']) { $edpost = array($a->get_baseurl($ssl_state) . "/editpost/" . $item['id'], t("Edit")); } else { $edpost = false; } if ($observer['xchan_hash'] == $this->get_data_value('author_xchan') || $observer['xchan_hash'] == $this->get_data_value('owner_xchan') || $this->get_data_value('uid') == local_user()) { $dropping = true; } if ($dropping) { $drop = array('dropping' => $dropping, 'delete' => t('Delete')); } // FIXME if ($observer_is_pageowner) { $multidrop = array('select' => t('Select')); } $filer = $conv->get_profile_owner() == local_user() ? t("Save to Folder") : false; $profile_avatar = $item['author']['xchan_photo_m']; $profile_link = chanlink_url($item['author']['xchan_url']); $profile_name = $item['author']['xchan_name']; $location = format_location($item); $like_count = x($alike, $item['mid']) ? $alike[$item['mid']] : ''; $like_list = x($alike, $item['mid']) ? $alike[$item['mid'] . '-l'] : ''; if (count($like_list) > MAX_LIKERS) { $like_list_part = array_slice($like_list, 0, MAX_LIKERS); array_push($like_list_part, '<a href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>'); } else { $like_list_part = ''; } $like_button_label = tt('Like', 'Likes', $like_count, 'noun'); if (feature_enabled($conv->get_profile_owner(), 'dislike')) { $dislike_count = x($dlike, $item['mid']) ? $dlike[$item['mid']] : ''; $dislike_list = x($dlike, $item['mid']) ? $dlike[$item['mid'] . '-l'] : ''; $dislike_button_label = tt('Dislike', 'Dislikes', $dislike_count, 'noun'); if (count($dislike_list) > MAX_LIKERS) { $dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS); array_push($dislike_list_part, '<a href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>'); } else { $dislike_list_part = ''; } } $showlike = x($alike, $item['mid']) ? format_like($alike[$item['mid']], $alike[$item['mid'] . '-l'], 'like', $item['mid']) : ''; $showdislike = x($dlike, $item['mid']) && feature_enabled($conv->get_profile_owner(), 'dislike') ? format_like($dlike[$item['mid']], $dlike[$item['mid'] . '-l'], 'dislike', $item['mid']) : ''; /* * We should avoid doing this all the time, but it depends on the conversation mode * And the conv mode may change when we change the conv, or it changes its mode * Maybe we should establish a way to be notified about conversation changes */ $this->check_wall_to_wall(); if ($this->is_toplevel()) { // FIXME check this permission if ($conv->get_profile_owner() == local_user()) { // FIXME we don't need all this stuff, some can be done in the template $star = array('do' => t("Add Star"), 'undo' => t("Remove Star"), 'toggle' => t("Toggle Star Status"), 'classdo' => $item['item_flags'] & ITEM_STARRED ? "hidden" : "", 'classundo' => $item['item_flags'] & ITEM_STARRED ? "" : "hidden", 'isstarred' => $item['item_flags'] & ITEM_STARRED ? "starred icon-star" : "unstarred icon-star-empty", 'starred' => t('starred')); } } else { $indent = 'comment'; } $verified = $item['item_flags'] & ITEM_VERIFIED ? t('Message is verified') : ''; $unverified = ''; // (($this->is_wall_to_wall() && (! ($item['item_flags'] & ITEM_VERIFIED))) ? t('Message cannot be verified') : ''); // FIXME - check this permission if ($conv->get_profile_owner() == local_user()) { $tagger = array('tagit' => t("Add Tag"), 'classtagger' => ""); } $has_bookmarks = false; if (is_array($item['term'])) { foreach ($item['term'] as $t) { if ($t['type'] == TERM_BOOKMARK) { $has_bookmarks = true; } } } $has_event = false; if ($item['obj_type'] === ACTIVITY_OBJ_EVENT && $conv->get_profile_owner() == local_user()) { $has_event = true; } if ($this->is_commentable()) { $like = array(t("I like this (toggle)"), t("like")); $dislike = array(t("I don't like this (toggle)"), t("dislike")); } if ($shareable) { $share = array(t('Share This'), t('share')); } if (strcmp(datetime_convert('UTC', 'UTC', $item['created']), datetime_convert('UTC', 'UTC', 'now - 12 hours')) > 0) { $indent .= ' shiny'; } $t2 = dba_timer(); localize_item($item); $t3 = dba_timer(); $body = prepare_body($item, true); $t4 = dba_timer(); $tmp_item = array('template' => $this->get_template(), 'mode' => $mode, 'type' => implode("", array_slice(explode("/", $item['verb']), -1)), 'tags' => array(), 'body' => $body, 'text' => strip_tags($body), 'id' => $this->get_id(), 'linktitle' => sprintf(t('View %s\'s profile - %s'), $profile_name, $item['author']['xchan_addr']), 'olinktitle' => sprintf(t('View %s\'s profile - %s'), $this->get_owner_name(), $item['owner']['xchan_addr']), 'to' => t('to'), 'via' => t('via'), 'wall' => t('Wall-to-Wall'), 'vwall' => t('via Wall-To-Wall:'), 'profile_url' => $profile_link, 'item_photo_menu' => item_photo_menu($item), 'name' => $profile_name, 'thumb' => $profile_avatar, 'osparkle' => $osparkle, 'sparkle' => $sparkle, 'title' => $item['title'], 'ago' => relative_date($item['created']), 'app' => $item['app'], 'str_app' => sprintf(t(' from %s'), $item['app']), 'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'), 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'), 'editedtime' => $item['edited'] != $item['created'] ? sprintf(t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : '', 'expiretime' => $item['expires'] !== NULL_DATE ? sprintf(t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')) : '', 'lock' => $lock, 'verified' => $verified, 'unverified' => $unverified, 'location' => $location, 'indent' => $indent, 'owner_url' => $this->get_owner_url(), 'owner_photo' => $this->get_owner_photo(), 'owner_name' => $this->get_owner_name(), 'like' => $like, 'dislike' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike : '', 'share' => $share, 'rawmid' => $item['mid'], 'plink' => get_plink($item), 'edpost' => feature_enabled($conv->get_profile_owner(), 'edit_posts') ? $edpost : '', 'star' => feature_enabled($conv->get_profile_owner(), 'star_posts') ? $star : '', 'tagger' => feature_enabled($conv->get_profile_owner(), 'commtag') ? $tagger : '', 'filer' => feature_enabled($conv->get_profile_owner(), 'filing') ? $filer : '', 'bookmark' => $conv->get_profile_owner() == local_user() && $has_bookmarks ? t('Save Bookmarks') : '', 'addtocal' => $has_event ? t('Add to Calendar') : '', 'drop' => $drop, 'multidrop' => feature_enabled($conv->get_profile_owner(), 'multi_delete') ? $multidrop : '', 'like_count' => $like_count, 'like_list' => $like_list, 'like_list_part' => $like_list_part, 'like_button_label' => $like_button_label, 'like_modal_title' => t('Likes', 'noun'), 'dislike_modal_title' => t('Dislikes', 'noun'), 'dislike_count' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_count : '', 'dislike_list' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_list : '', 'dislike_list_part' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_list_part : '', 'dislike_button_label' => feature_enabled($conv->get_profile_owner(), 'dislike') ? $dislike_button_label : '', 'modal_dismiss' => t('Close'), 'showlike' => $showlike, 'showdislike' => $showdislike, 'comment' => $this->get_comment_box($indent), 'previewing' => $conv->is_preview() ? ' preview ' : '', 'wait' => t('Please wait'), 'thread_level' => $thread_level); $t5 = dba_timer(); $arr = array('item' => $item, 'output' => $tmp_item); call_hooks('display_item', $arr); $result = $arr['output']; $result['children'] = array(); $children = $this->get_children(); $nb_children = count($children); if ($nb_children > 0) { foreach ($children as $child) { $result['children'][] = $child->get_template_data($alike, $dlike, $thread_level + 1); } // Collapse if ($nb_children > 2 || $thread_level > 1) { $result['children'][0]['comment_firstcollapsed'] = true; $result['children'][0]['num_comments'] = sprintf(tt('%d comment', '%d comments', $total_children), $total_children); $result['children'][0]['hide_text'] = t('[+] show all'); if ($thread_level > 1) { $result['children'][$nb_children - 1]['comment_lastcollapsed'] = true; } else { $result['children'][$nb_children - 3]['comment_lastcollapsed'] = true; } } } $result['private'] = $item['item_private']; $result['toplevel'] = $this->is_toplevel() ? 'toplevel_item' : ''; if ($this->is_threaded()) { $result['flatten'] = false; $result['threaded'] = true; } else { $result['flatten'] = true; $result['threaded'] = false; } $t6 = dba_timer(); // profiler($t1,$t2,'t2'); // profiler($t2,$t3,'t3'); // profiler($t3,$t4,'t4'); // profiler($t4,$t5,'t5'); // profiler($t5,$t6,'t6'); // profiler($t1,$t6,'item total'); return $result; }