Exemplo n.º 1
0
function get_atom_elements($feed, $item, $contact = array())
{
    require_once 'library/HTMLPurifier.auto.php';
    require_once 'include/html2bbcode.php';
    $best_photo = array();
    $res = array();
    $author = $item->get_author();
    if ($author) {
        $res['author-name'] = unxmlify($author->get_name());
        $res['author-link'] = unxmlify($author->get_link());
    } else {
        $res['author-name'] = unxmlify($feed->get_title());
        $res['author-link'] = unxmlify($feed->get_permalink());
    }
    $res['uri'] = unxmlify($item->get_id());
    $res['title'] = unxmlify($item->get_title());
    $res['body'] = unxmlify($item->get_content());
    $res['plink'] = unxmlify($item->get_link(0));
    if (isset($contact["network"]) and $contact["network"] == NETWORK_FEED and strstr($res['plink'], ".app.net/")) {
        logger("get_atom_elements: detected app.net posting: " . print_r($res, true), LOGGER_DEBUG);
        $res['title'] = "";
        $res['body'] = nl2br($res['body']);
    }
    // removing the content of the title if its identically to the body
    // This helps with auto generated titles e.g. from tumblr
    if (title_is_body($res["title"], $res["body"])) {
        $res['title'] = "";
    }
    if ($res['plink']) {
        $base_url = implode('/', array_slice(explode('/', $res['plink']), 0, 3));
    } else {
        $base_url = '';
    }
    // look for a photo. We should check media size and find the best one,
    // but for now let's just find any author photo
    // Additionally we look for an alternate author link. On OStatus this one is the one we want.
    $authorlinks = $item->feed->data["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["feed"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["author"][0]["child"]["http://www.w3.org/2005/Atom"]["link"];
    if (is_array($authorlinks)) {
        foreach ($authorlinks as $link) {
            $linkdata = array_shift($link["attribs"]);
            if ($linkdata["rel"] == "alternate") {
                $res["author-link"] = $linkdata["href"];
            }
        }
    }
    $rawauthor = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
    if ($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
        $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
        foreach ($base as $link) {
            if ($link['attribs']['']['rel'] === 'alternate') {
                $res['author-link'] = unxmlify($link['attribs']['']['href']);
            }
            if (!x($res, 'author-avatar') || !$res['author-avatar']) {
                if ($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
                    $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
                }
            }
        }
    }
    $rawactor = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor');
    if ($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['object-type'][0]['data'], ACTIVITY_OBJ_PERSON)) {
        $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
        if ($base && count($base)) {
            foreach ($base as $link) {
                if ($link['attribs']['']['rel'] === 'alternate' && !$res['author-link']) {
                    $res['author-link'] = unxmlify($link['attribs']['']['href']);
                }
                if (!x($res, 'author-avatar') || !$res['author-avatar']) {
                    if ($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo') {
                        $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
                    }
                }
            }
        }
    }
    // No photo/profile-link on the item - look at the feed level
    if (!x($res, 'author-link') || !x($res, 'author-avatar')) {
        $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
        if ($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
            $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
            foreach ($base as $link) {
                if ($link['attribs']['']['rel'] === 'alternate' && !$res['author-link']) {
                    $res['author-link'] = unxmlify($link['attribs']['']['href']);
                }
                if (!$res['author-avatar']) {
                    if ($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
                        $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
                    }
                }
            }
        }
        $rawactor = $feed->get_feed_tags(NAMESPACE_ACTIVITY, 'subject');
        if ($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['object-type'][0]['data'], ACTIVITY_OBJ_PERSON)) {
            $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
            if ($base && count($base)) {
                foreach ($base as $link) {
                    if ($link['attribs']['']['rel'] === 'alternate' && !$res['author-link']) {
                        $res['author-link'] = unxmlify($link['attribs']['']['href']);
                    }
                    if (!x($res, 'author-avatar')) {
                        if ($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo') {
                            $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
                        }
                    }
                }
            }
        }
    }
    $apps = $item->get_item_tags(NAMESPACE_STATUSNET, 'notice_info');
    if ($apps && $apps[0]['attribs']['']['source']) {
        $res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source']));
        if ($res['app'] === 'web') {
            $res['app'] = 'OStatus';
        }
    }
    // base64 encoded json structure representing Diaspora signature
    $dsig = $item->get_item_tags(NAMESPACE_DFRN, 'diaspora_signature');
    if ($dsig) {
        $res['dsprsig'] = unxmlify($dsig[0]['data']);
    }
    $dguid = $item->get_item_tags(NAMESPACE_DFRN, 'diaspora_guid');
    if ($dguid) {
        $res['guid'] = unxmlify($dguid[0]['data']);
    }
    $bm = $item->get_item_tags(NAMESPACE_DFRN, 'bookmark');
    if ($bm) {
        $res['bookmark'] = unxmlify($bm[0]['data']) === 'true' ? 1 : 0;
    }
    /**
     * If there's a copy of the body content which is guaranteed to have survived mangling in transit, use it.
     */
    $have_real_body = false;
    $rawenv = $item->get_item_tags(NAMESPACE_DFRN, 'env');
    if ($rawenv) {
        $have_real_body = true;
        $res['body'] = $rawenv[0]['data'];
        $res['body'] = str_replace(array(' ', "\t", "\r", "\n"), array('', '', '', ''), $res['body']);
        // make sure nobody is trying to sneak some html tags by us
        $res['body'] = notags(base64url_decode($res['body']));
    }
    $res['body'] = limit_body_size($res['body']);
    // It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust
    // the content type. Our own network only emits text normally, though it might have been converted to
    // html if we used a pubsubhubbub transport. But if we see even one html tag in our text, we will
    // have to assume it is all html and needs to be purified.
    // It doesn't matter all that much security wise - because before this content is used anywhere, we are
    // going to escape any tags we find regardless, but this lets us import a limited subset of html from
    // the wild, by sanitising it and converting supported tags to bbcode before we rip out any remaining
    // html.
    if (strpos($res['body'], '<') !== false && strpos($res['body'], '>') !== false) {
        $res['body'] = reltoabs($res['body'], $base_url);
        $res['body'] = html2bb_video($res['body']);
        $res['body'] = oembed_html2bbcode($res['body']);
        $config = HTMLPurifier_Config::createDefault();
        $config->set('Cache.DefinitionImpl', null);
        // we shouldn't need a whitelist, because the bbcode converter
        // will strip out any unsupported tags.
        $purifier = new HTMLPurifier($config);
        $res['body'] = $purifier->purify($res['body']);
        $res['body'] = @html2bbcode($res['body']);
    } elseif (!$have_real_body) {
        // it's not one of our messages and it has no tags
        // so it's probably just text. We'll escape it just to be safe.
        $res['body'] = escape_tags($res['body']);
    }
    // this tag is obsolete but we keep it for really old sites
    $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
    if ($allow && $allow[0]['data'] == 1) {
        $res['last-child'] = 1;
    } else {
        $res['last-child'] = 0;
    }
    $private = $item->get_item_tags(NAMESPACE_DFRN, 'private');
    if ($private && intval($private[0]['data']) > 0) {
        $res['private'] = intval($private[0]['data']);
    } else {
        $res['private'] = 0;
    }
    $extid = $item->get_item_tags(NAMESPACE_DFRN, 'extid');
    if ($extid && $extid[0]['data']) {
        $res['extid'] = $extid[0]['data'];
    }
    $rawlocation = $item->get_item_tags(NAMESPACE_DFRN, 'location');
    if ($rawlocation) {
        $res['location'] = unxmlify($rawlocation[0]['data']);
    }
    $rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published');
    if ($rawcreated) {
        $res['created'] = unxmlify($rawcreated[0]['data']);
    }
    $rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated');
    if ($rawedited) {
        $res['edited'] = unxmlify($rawedited[0]['data']);
    }
    if (x($res, 'edited') && !x($res, 'created')) {
        $res['created'] = $res['edited'];
    }
    if (!$res['created']) {
        $res['created'] = $item->get_date('c');
    }
    if (!$res['edited']) {
        $res['edited'] = $item->get_date('c');
    }
    // Disallow time travelling posts
    $d1 = strtotime($res['created']);
    $d2 = strtotime($res['edited']);
    $d3 = strtotime('now');
    if ($d1 > $d3) {
        $res['created'] = datetime_convert();
    }
    if ($d2 > $d3) {
        $res['edited'] = datetime_convert();
    }
    $rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner');
    if ($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']) {
        $res['owner-name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']);
    } elseif ($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']) {
        $res['owner-name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']);
    }
    if ($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']) {
        $res['owner-link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']);
    } elseif ($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']) {
        $res['owner-link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']);
    }
    if ($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
        $base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
        foreach ($base as $link) {
            if (!x($res, 'owner-avatar') || !$res['owner-avatar']) {
                if ($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
                    $res['owner-avatar'] = unxmlify($link['attribs']['']['href']);
                }
            }
        }
    }
    $rawgeo = $item->get_item_tags(NAMESPACE_GEORSS, 'point');
    if ($rawgeo) {
        $res['coord'] = unxmlify($rawgeo[0]['data']);
    }
    if ($contact["network"] == NETWORK_FEED) {
        $res['verb'] = ACTIVITY_POST;
        $res['object-type'] = ACTIVITY_OBJ_NOTE;
    }
    $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb');
    // select between supported verbs
    if ($rawverb) {
        $res['verb'] = unxmlify($rawverb[0]['data']);
    }
    // translate OStatus unfollow to activity streams if it happened to get selected
    if (x($res, 'verb') && $res['verb'] === 'http://ostatus.org/schema/1.0/unfollow') {
        $res['verb'] = ACTIVITY_UNFOLLOW;
    }
    $cats = $item->get_categories();
    if ($cats) {
        $tag_arr = array();
        foreach ($cats as $cat) {
            $term = $cat->get_term();
            if (!$term) {
                $term = $cat->get_label();
            }
            $scheme = $cat->get_scheme();
            if ($scheme && $term && stristr($scheme, 'X-DFRN:')) {
                $tag_arr[] = substr($scheme, 7, 1) . '[url=' . unxmlify(substr($scheme, 9)) . ']' . unxmlify($term) . '[/url]';
            } elseif ($term) {
                $tag_arr[] = notags(trim($term));
            }
        }
        $res['tag'] = implode(',', $tag_arr);
    }
    $attach = $item->get_enclosures();
    if ($attach) {
        $att_arr = array();
        foreach ($attach as $att) {
            $len = intval($att->get_length());
            $link = str_replace(array(',', '"'), array('%2D', '%22'), notags(trim(unxmlify($att->get_link()))));
            $title = str_replace(array(',', '"'), array('%2D', '%22'), notags(trim(unxmlify($att->get_title()))));
            $type = str_replace(array(',', '"'), array('%2D', '%22'), notags(trim(unxmlify($att->get_type()))));
            if (strpos($type, ';')) {
                $type = substr($type, 0, strpos($type, ';'));
            }
            if (!$link || strpos($link, 'http') !== 0) {
                continue;
            }
            if (!$title) {
                $title = ' ';
            }
            if (!$type) {
                $type = 'application/octet-stream';
            }
            $att_arr[] = '[attach]href="' . $link . '" length="' . $len . '" type="' . $type . '" title="' . $title . '"[/attach]';
        }
        $res['attach'] = implode(',', $att_arr);
    }
    $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
    if ($rawobj) {
        $res['object'] = '<object>' . "\n";
        $child = $rawobj[0]['child'];
        if ($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) {
            $res['object-type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'];
            $res['object'] .= '<type>' . $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'] . '</type>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) {
            $res['object'] .= '<id>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'] . '</id>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
            $res['object'] .= '<link>' . encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) . '</link>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']) {
            $res['object'] .= '<title>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'] . '</title>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
            $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
            if (!$body) {
                $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
            }
            // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
            $res['object'] .= '<orig>' . xmlify($body) . '</orig>' . "\n";
            if (strpos($body, '<') !== false || strpos($body, '>') !== false) {
                $body = html2bb_video($body);
                $config = HTMLPurifier_Config::createDefault();
                $config->set('Cache.DefinitionImpl', null);
                $purifier = new HTMLPurifier($config);
                $body = $purifier->purify($body);
                $body = html2bbcode($body);
            }
            $res['object'] .= '<content>' . $body . '</content>' . "\n";
        }
        $res['object'] .= '</object>' . "\n";
    }
    $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'target');
    if ($rawobj) {
        $res['target'] = '<target>' . "\n";
        $child = $rawobj[0]['child'];
        if ($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) {
            $res['target'] .= '<type>' . $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'] . '</type>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) {
            $res['target'] .= '<id>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'] . '</id>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
            $res['target'] .= '<link>' . encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) . '</link>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'data') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']) {
            $res['target'] .= '<title>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'] . '</title>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'data') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
            $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
            if (!$body) {
                $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
            }
            // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
            $res['target'] .= '<orig>' . xmlify($body) . '</orig>' . "\n";
            if (strpos($body, '<') !== false || strpos($body, '>') !== false) {
                $body = html2bb_video($body);
                $config = HTMLPurifier_Config::createDefault();
                $config->set('Cache.DefinitionImpl', null);
                $purifier = new HTMLPurifier($config);
                $body = $purifier->purify($body);
                $body = html2bbcode($body);
            }
            $res['target'] .= '<content>' . $body . '</content>' . "\n";
        }
        $res['target'] .= '</target>' . "\n";
    }
    // This is some experimental stuff. By now retweets are shown with "RT:"
    // But: There is data so that the message could be shown similar to native retweets
    // There is some better way to parse this array - but it didn't worked for me.
    $child = $item->feed->data["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["feed"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["entry"][0]["child"]["http://activitystrea.ms/spec/1.0/"][object][0]["child"];
    if (is_array($child)) {
        logger('get_atom_elements: Looking for status.net repeated message');
        $message = $child["http://activitystrea.ms/spec/1.0/"]["object"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["content"][0]["data"];
        $orig_id = ostatus_convert_href($child["http://activitystrea.ms/spec/1.0/"]["object"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["id"][0]["data"]);
        $author = $child[SIMPLEPIE_NAMESPACE_ATOM_10]["author"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10];
        $uri = $author["uri"][0]["data"];
        $name = $author["name"][0]["data"];
        $avatar = @array_shift($author["link"][2]["attribs"]);
        $avatar = $avatar["href"];
        if ($name != "" and $uri != "" and $avatar != "" and $message != "") {
            logger('get_atom_elements: fixing sender of repeated message. ' . $orig_id, LOGGER_DEBUG);
            if (!intval(get_config('system', 'wall-to-wall_share'))) {
                $prefix = share_header($name, $uri, $avatar, "", "", $orig_link);
                $res["body"] = $prefix . html2bbcode($message) . "[/share]";
            } else {
                $res["owner-name"] = $res["author-name"];
                $res["owner-link"] = $res["author-link"];
                $res["owner-avatar"] = $res["author-avatar"];
                $res["author-name"] = $name;
                $res["author-link"] = $uri;
                $res["author-avatar"] = $avatar;
                $res["body"] = html2bbcode($message);
            }
        }
    }
    if (isset($contact["network"]) and $contact["network"] == NETWORK_FEED and $contact['fetch_further_information']) {
        $preview = "";
        // Handle enclosures and treat them as preview picture
        if (isset($attach)) {
            foreach ($attach as $attachment) {
                if ($attachment->type == "image/jpeg") {
                    $preview = $attachment->link;
                }
            }
        }
        $res["body"] = $res["title"] . add_page_info($res['plink'], false, $preview, $contact['fetch_further_information'] == 2, $contact['ffi_keyword_blacklist']);
        $res["tag"] = add_page_keywords($res['plink'], false, $preview, $contact['fetch_further_information'] == 2, $contact['ffi_keyword_blacklist']);
        $res["title"] = "";
        $res["object-type"] = ACTIVITY_OBJ_BOOKMARK;
        unset($res["attach"]);
    } elseif (isset($contact["network"]) and $contact["network"] == NETWORK_OSTATUS) {
        $res["body"] = add_page_info_to_body($res["body"]);
    } elseif (isset($contact["network"]) and $contact["network"] == NETWORK_FEED and strstr($res['plink'], ".app.net/")) {
        $res["body"] = add_page_info_to_body($res["body"]);
    }
    $arr = array('feed' => $feed, 'item' => $item, 'result' => $res);
    call_hooks('parse_atom', $arr);
    return $res;
}
Exemplo n.º 2
0
/**
 * @param object $feed
 * @param array $item
 * @param[out] array $author
 * @return multitype:multitype: string NULL number Ambigous <NULL, string, number> Ambigous <mixed, string> Ambigous <multitype:multitype:string Ambigous <NULL, string>  , multitype:multitype:string unknown  > multitype:NULL unknown
 */
function get_atom_elements($feed, $item, &$author)
{
    //$best_photo = array();
    $res = array();
    $found_author = $item->get_author();
    if ($found_author) {
        $author['author_name'] = unxmlify($found_author->get_name());
        $author['author_link'] = unxmlify($found_author->get_link());
        $author['author_is_feed'] = false;
    } else {
        $author['author_name'] = unxmlify($feed->get_title());
        $author['author_link'] = unxmlify($feed->get_permalink());
        $author['author_is_feed'] = true;
    }
    if (substr($author['author_link'], -1, 1) == '/') {
        $author['author_link'] = substr($author['author_link'], 0, -1);
    }
    $res['mid'] = base64url_encode(unxmlify($item->get_id()));
    $res['title'] = unxmlify($item->get_title());
    $res['body'] = unxmlify($item->get_content());
    $res['plink'] = unxmlify($item->get_link(0));
    $res['item_flags'] = ITEM_RSS;
    // removing the content of the title if its identically to the body
    // This helps with auto generated titles e.g. from tumblr
    if (title_is_body($res["title"], $res["body"])) {
        $res['title'] = "";
    }
    if ($res['plink']) {
        $base_url = implode('/', array_slice(explode('/', $res['plink']), 0, 3));
    } else {
        $base_url = '';
    }
    // look for a photo. We should check media size and find the best one,
    // but for now let's just find any author photo
    $rawauthor = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
    if ($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
        $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
        foreach ($base as $link) {
            if (!x($author, 'author_photo') || !$author['author_photo']) {
                if ($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
                    $author['author_photo'] = unxmlify($link['attribs']['']['href']);
                }
            }
        }
    }
    $rawactor = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor');
    if ($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['obj_type'][0]['data'], ACTIVITY_OBJ_PERSON)) {
        $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
        if ($base && count($base)) {
            foreach ($base as $link) {
                if ($link['attribs']['']['rel'] === 'alternate' && !$res['author_link']) {
                    $author['author_link'] = unxmlify($link['attribs']['']['href']);
                }
                if (!x($author, 'author_photo') || !$author['author_photo']) {
                    if ($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo') {
                        $author['author_photo'] = unxmlify($link['attribs']['']['href']);
                    }
                }
            }
        }
    }
    // check for a yahoo media element (github etc.)
    if (!$author['author_photo']) {
        $rawmedia = $item->get_item_tags(NAMESPACE_YMEDIA, 'thumbnail');
        if ($rawmedia && $rawmedia[0]['attribs']['']['url']) {
            $author['author_photo'] = strip_tags(unxmlify($rawmedia[0]['attribs']['']['url']));
        }
    }
    // No photo/profile-link on the item - look at the feed level
    if (!x($author, 'author_link') || !x($author, 'author_photo')) {
        $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
        if ($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
            $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
            foreach ($base as $link) {
                if ($link['attribs']['']['rel'] === 'alternate' && !$author['author_link']) {
                    $author['author_link'] = unxmlify($link['attribs']['']['href']);
                    $author['author_is_feed'] = true;
                }
                if (!$author['author_photo']) {
                    if ($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
                        $author['author_photo'] = unxmlify($link['attribs']['']['href']);
                    }
                }
            }
        }
        $rawactor = $feed->get_feed_tags(NAMESPACE_ACTIVITY, 'subject');
        if ($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['obj_type'][0]['data'], ACTIVITY_OBJ_PERSON)) {
            $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
            if ($base && count($base)) {
                foreach ($base as $link) {
                    if ($link['attribs']['']['rel'] === 'alternate' && !$res['author_link']) {
                        $author['author_link'] = unxmlify($link['attribs']['']['href']);
                    }
                    if (!x($author, 'author_photo')) {
                        if ($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo') {
                            $author['author_photo'] = unxmlify($link['attribs']['']['href']);
                        }
                    }
                }
            }
        }
    }
    $apps = $item->get_item_tags(NAMESPACE_STATUSNET, 'notice_info');
    if ($apps && $apps[0]['attribs']['']['source']) {
        $res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source']));
    }
    /*
     * If there's a copy of the body content which is guaranteed to have survived mangling in transit, use it.
     */
    $have_real_body = false;
    $rawenv = $item->get_item_tags(NAMESPACE_DFRN, 'env');
    if ($rawenv) {
        $have_real_body = true;
        $res['body'] = $rawenv[0]['data'];
        $res['body'] = str_replace(array(' ', "\t", "\r", "\n"), array('', '', '', ''), $res['body']);
        // make sure nobody is trying to sneak some html tags by us
        $res['body'] = notags(base64url_decode($res['body']));
        // We could probably turn these old Friendica bbcode bookmarks into bookmark tags but we'd have to
        // create a term table item for them. For now just make sure they stay as links.
        $res['body'] = preg_replace('/\\[bookmark(.*?)\\](.*?)\\[\\/bookmark\\]/', '[url$1]$2[/url]', $res['body']);
    }
    $res['body'] = limit_body_size($res['body']);
    // It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust
    // the content type. Our own network only emits text normally, though it might have been converted to
    // html if we used a pubsubhubbub transport. But if we see even one html tag in our text, we will
    // have to assume it is all html and needs to be purified.
    // It doesn't matter all that much security wise - because before this content is used anywhere, we are
    // going to escape any tags we find regardless, but this lets us import a limited subset of html from
    // the wild, by sanitising it and converting supported tags to bbcode before we rip out any remaining
    // html.
    if (strpos($res['body'], '<') !== false && strpos($res['body'], '>') !== false) {
        $res['body'] = reltoabs($res['body'], $base_url);
        $res['body'] = html2bb_video($res['body']);
        $res['body'] = oembed_html2bbcode($res['body']);
        $res['body'] = purify_html($res['body']);
        $res['body'] = @html2bbcode($res['body']);
    } elseif (!$have_real_body) {
        // it's not one of our messages and it has no tags
        // so it's probably just text. We'll escape it just to be safe.
        $res['body'] = escape_tags($res['body']);
    }
    if ($res['plink'] && $res['title']) {
        $res['body'] = '#^[url=' . $res['plink'] . ']' . $res['title'] . '[/url]' . "\n\n" . $res['body'];
        $terms = array();
        $terms[] = array('otype' => TERM_OBJ_POST, 'type' => TERM_BOOKMARK, 'url' => $res['plink'], 'term' => $res['title']);
    } elseif ($res['plink']) {
        $res['body'] = '#^[url]' . $res['plink'] . '[/url]' . "\n\n" . $res['body'];
        $terms = array();
        $terms[] = array('otype' => TERM_OBJ_POST, 'type' => TERM_BOOKMARK, 'url' => $res['plink'], 'term' => $res['plink']);
    }
    $private = $item->get_item_tags(NAMESPACE_DFRN, 'private');
    if ($private && intval($private[0]['data']) > 0) {
        $res['item_private'] = intval($private[0]['data']) ? 1 : 0;
    } else {
        $res['item_private'] = 0;
    }
    $rawlocation = $item->get_item_tags(NAMESPACE_DFRN, 'location');
    if ($rawlocation) {
        $res['location'] = unxmlify($rawlocation[0]['data']);
    }
    $rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published');
    if ($rawcreated) {
        $res['created'] = unxmlify($rawcreated[0]['data']);
    }
    $rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated');
    if ($rawedited) {
        $res['edited'] = unxmlify($rawedited[0]['data']);
    }
    if (x($res, 'edited') && !x($res, 'created')) {
        $res['created'] = $res['edited'];
    }
    if (!$res['created']) {
        $res['created'] = $item->get_date('c');
    }
    if (!$res['edited']) {
        $res['edited'] = $item->get_date('c');
    }
    // Disallow time travelling posts
    $d1 = strtotime($res['created']);
    $d2 = strtotime($res['edited']);
    $d3 = strtotime('now');
    if ($d1 > $d3) {
        $res['created'] = datetime_convert();
    }
    if ($d2 > $d3) {
        $res['edited'] = datetime_convert();
    }
    $res['created'] = datetime_convert('UTC', 'UTC', $res['created']);
    $res['edited'] = datetime_convert('UTC', 'UTC', $res['edited']);
    $rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner');
    if (!$rawowner) {
        $rawowner = $item->get_item_tags(NAMESPACE_ZOT, 'owner');
    }
    if ($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']) {
        $author['owner_name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']);
    } elseif ($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']) {
        $author['owner_name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']);
    }
    if ($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']) {
        $author['owner_link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']);
    } elseif ($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']) {
        $author['owner_link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']);
    }
    if ($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
        $base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
        foreach ($base as $link) {
            if (!x($author, 'owner_photo') || !$author['owner_photo']) {
                if ($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
                    $author['owner_photo'] = unxmlify($link['attribs']['']['href']);
                }
            }
        }
    }
    $rawgeo = $item->get_item_tags(NAMESPACE_GEORSS, 'point');
    if ($rawgeo) {
        $res['coord'] = unxmlify($rawgeo[0]['data']);
    }
    $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb');
    // select between supported verbs
    if ($rawverb) {
        $res['verb'] = unxmlify($rawverb[0]['data']);
    }
    // translate OStatus unfollow to activity streams if it happened to get selected
    if (x($res, 'verb') && $res['verb'] === 'http://ostatus.org/schema/1.0/unfollow') {
        $res['verb'] = ACTIVITY_UNFOLLOW;
    }
    $cats = $item->get_categories();
    if ($cats) {
        if (is_null($terms)) {
            $terms = array();
        }
        foreach ($cats as $cat) {
            $term = $cat->get_term();
            if (!$term) {
                $term = $cat->get_label();
            }
            $scheme = $cat->get_scheme();
            $termurl = '';
            if ($scheme && $term && stristr($scheme, 'X-DFRN:')) {
                $termtype = substr($scheme, 7, 1) === '#' ? TERM_HASHTAG : TERM_MENTION;
                $termurl = unxmlify(substr($scheme, 9));
            } else {
                $termtype = TERM_CATEGORY;
            }
            $termterm = notags(trim(unxmlify($term)));
            if ($termterm) {
                $terms[] = array('otype' => TERM_OBJ_POST, 'type' => $termtype, 'url' => $termurl, 'term' => $termterm);
            }
        }
    }
    if (!is_null($terms)) {
        $res['term'] = $terms;
    }
    $attach = $item->get_enclosures();
    if ($attach) {
        $res['attach'] = array();
        foreach ($attach as $att) {
            $len = intval($att->get_length());
            $link = str_replace(array(',', '"'), array('%2D', '%22'), notags(trim(unxmlify($att->get_link()))));
            $title = str_replace(array(',', '"'), array('%2D', '%22'), notags(trim(unxmlify($att->get_title()))));
            $type = str_replace(array(',', '"'), array('%2D', '%22'), notags(trim(unxmlify($att->get_type()))));
            if (strpos($type, ';')) {
                $type = substr($type, 0, strpos($type, ';'));
            }
            if (!$link || strpos($link, 'http') !== 0) {
                continue;
            }
            if (!$title) {
                $title = ' ';
            }
            if (!$type) {
                $type = 'application/octet-stream';
            }
            $res['attach'][] = array('href' => $link, 'length' => $len, 'type' => $type, 'title' => $title);
        }
    }
    $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
    if ($rawobj) {
        $obj = array();
        $child = $rawobj[0]['child'];
        if ($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) {
            $res['obj_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
            $obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) {
            $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'];
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
            $obj['link'] = encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']);
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']) {
            $obj['title'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'];
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
            $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
            if (!$body) {
                $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
            }
            // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
            $obj['orig'] = xmlify($body);
            if (strpos($body, '<') !== false || strpos($body, '>') !== false) {
                $body = purify_html($body);
                $body = html2bbcode($body);
            }
            $obj['content'] = $body;
        }
        $res['object'] = $obj;
    }
    $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'target');
    if ($rawobj) {
        $obj = array();
        $child = $rawobj[0]['child'];
        if ($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) {
            $res['tgt_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
            $obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) {
            $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'];
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
            $obj['link'] = encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']);
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']) {
            $obj['title'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'];
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
            $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
            if (!$body) {
                $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
            }
            // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
            $obj['orig'] = xmlify($body);
            if (strpos($body, '<') !== false || strpos($body, '>') !== false) {
                $body = purify_html($body);
                $body = html2bbcode($body);
            }
            $obj['content'] = $body;
        }
        $res['target'] = $obj;
    }
    $res['public_policy'] = 'specific';
    $res['comment_policy'] = 'none';
    $arr = array('feed' => $feed, 'item' => $item, 'result' => $res);
    call_hooks('parse_atom', $arr);
    logger('get_atom_elements: author: ' . print_r($author, true), LOGGER_DATA);
    logger('get_atom_elements: ' . print_r($res, true), LOGGER_DATA);
    return $res;
}
Exemplo n.º 3
0
function get_atom_elements($feed, $item)
{
    require_once 'library/HTMLPurifier.auto.php';
    require_once 'include/html2bbcode.php';
    $best_photo = array();
    $res = array();
    $author = $item->get_author();
    if ($author) {
        $res['author-name'] = unxmlify($author->get_name());
        $res['author-link'] = unxmlify($author->get_link());
    } else {
        $res['author-name'] = unxmlify($feed->get_title());
        $res['author-link'] = unxmlify($feed->get_permalink());
    }
    $res['uri'] = unxmlify($item->get_id());
    $res['title'] = unxmlify($item->get_title());
    $res['body'] = unxmlify($item->get_content());
    $res['plink'] = unxmlify($item->get_link(0));
    if ($res['plink']) {
        $base_url = implode('/', array_slice(explode('/', $res['plink']), 0, 3));
    } else {
        $base_url = '';
    }
    // look for a photo. We should check media size and find the best one,
    // but for now let's just find any author photo
    $rawauthor = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
    if ($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
        $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
        foreach ($base as $link) {
            if (!x($res, 'author-avatar') || !$res['author-avatar']) {
                if ($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
                    $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
                }
            }
        }
    }
    $rawactor = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor');
    if ($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['object-type'][0]['data'], ACTIVITY_OBJ_PERSON)) {
        $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
        if ($base && count($base)) {
            foreach ($base as $link) {
                if ($link['attribs']['']['rel'] === 'alternate' && !$res['author-link']) {
                    $res['author-link'] = unxmlify($link['attribs']['']['href']);
                }
                if (!x($res, 'author-avatar') || !$res['author-avatar']) {
                    if ($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo') {
                        $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
                    }
                }
            }
        }
    }
    // No photo/profile-link on the item - look at the feed level
    if (!x($res, 'author-link') || !x($res, 'author-avatar')) {
        $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
        if ($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
            $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
            foreach ($base as $link) {
                if ($link['attribs']['']['rel'] === 'alternate' && !$res['author-link']) {
                    $res['author-link'] = unxmlify($link['attribs']['']['href']);
                }
                if (!$res['author-avatar']) {
                    if ($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
                        $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
                    }
                }
            }
        }
        $rawactor = $feed->get_feed_tags(NAMESPACE_ACTIVITY, 'subject');
        if ($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['object-type'][0]['data'], ACTIVITY_OBJ_PERSON)) {
            $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
            if ($base && count($base)) {
                foreach ($base as $link) {
                    if ($link['attribs']['']['rel'] === 'alternate' && !$res['author-link']) {
                        $res['author-link'] = unxmlify($link['attribs']['']['href']);
                    }
                    if (!x($res, 'author-avatar')) {
                        if ($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo') {
                            $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
                        }
                    }
                }
            }
        }
    }
    $apps = $item->get_item_tags(NAMESPACE_STATUSNET, 'notice_info');
    if ($apps && $apps[0]['attribs']['']['source']) {
        $res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source']));
        if ($res['app'] === 'web') {
            $res['app'] = 'OStatus';
        }
    }
    // base64 encoded json structure representing Diaspora signature
    $dsig = $item->get_item_tags(NAMESPACE_DFRN, 'diaspora_signature');
    if ($dsig) {
        $res['dsprsig'] = unxmlify($dsig[0]['data']);
    }
    $dguid = $item->get_item_tags(NAMESPACE_DFRN, 'diaspora_guid');
    if ($dguid) {
        $res['guid'] = unxmlify($dguid[0]['data']);
    }
    $bm = $item->get_item_tags(NAMESPACE_DFRN, 'bookmark');
    if ($bm) {
        $res['bookmark'] = unxmlify($bm[0]['data']) === 'true' ? 1 : 0;
    }
    /**
     * If there's a copy of the body content which is guaranteed to have survived mangling in transit, use it.
     */
    $have_real_body = false;
    $rawenv = $item->get_item_tags(NAMESPACE_DFRN, 'env');
    if ($rawenv) {
        $have_real_body = true;
        $res['body'] = $rawenv[0]['data'];
        $res['body'] = str_replace(array(' ', "\t", "\r", "\n"), array('', '', '', ''), $res['body']);
        // make sure nobody is trying to sneak some html tags by us
        $res['body'] = notags(base64url_decode($res['body']));
    }
    $maxlen = get_max_import_size();
    if ($maxlen && strlen($res['body']) > $maxlen) {
        $res['body'] = substr($res['body'], 0, $maxlen);
    }
    // It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust
    // the content type. Our own network only emits text normally, though it might have been converted to
    // html if we used a pubsubhubbub transport. But if we see even one html tag in our text, we will
    // have to assume it is all html and needs to be purified.
    // It doesn't matter all that much security wise - because before this content is used anywhere, we are
    // going to escape any tags we find regardless, but this lets us import a limited subset of html from
    // the wild, by sanitising it and converting supported tags to bbcode before we rip out any remaining
    // html.
    if (strpos($res['body'], '<') !== false && strpos($res['body'], '>') !== false) {
        $res['body'] = reltoabs($res['body'], $base_url);
        $res['body'] = html2bb_video($res['body']);
        $res['body'] = oembed_html2bbcode($res['body']);
        $config = HTMLPurifier_Config::createDefault();
        $config->set('Cache.DefinitionImpl', null);
        // we shouldn't need a whitelist, because the bbcode converter
        // will strip out any unsupported tags.
        $purifier = new HTMLPurifier($config);
        $res['body'] = $purifier->purify($res['body']);
        $res['body'] = @html2bbcode($res['body']);
    } elseif (!$have_real_body) {
        // it's not one of our messages and it has no tags
        // so it's probably just text. We'll escape it just to be safe.
        $res['body'] = escape_tags($res['body']);
    }
    // this tag is obsolete but we keep it for really old sites
    $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
    if ($allow && $allow[0]['data'] == 1) {
        $res['last-child'] = 1;
    } else {
        $res['last-child'] = 0;
    }
    $private = $item->get_item_tags(NAMESPACE_DFRN, 'private');
    if ($private && $private[0]['data'] == 1) {
        $res['private'] = 1;
    } else {
        $res['private'] = 0;
    }
    $extid = $item->get_item_tags(NAMESPACE_DFRN, 'extid');
    if ($extid && $extid[0]['data']) {
        $res['extid'] = $extid[0]['data'];
    }
    $rawlocation = $item->get_item_tags(NAMESPACE_DFRN, 'location');
    if ($rawlocation) {
        $res['location'] = unxmlify($rawlocation[0]['data']);
    }
    $rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published');
    if ($rawcreated) {
        $res['created'] = unxmlify($rawcreated[0]['data']);
    }
    $rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated');
    if ($rawedited) {
        $res['edited'] = unxmlify($rawedited[0]['data']);
    }
    if (x($res, 'edited') && !x($res, 'created')) {
        $res['created'] = $res['edited'];
    }
    if (!$res['created']) {
        $res['created'] = $item->get_date('c');
    }
    if (!$res['edited']) {
        $res['edited'] = $item->get_date('c');
    }
    // Disallow time travelling posts
    $d1 = strtotime($res['created']);
    $d2 = strtotime($res['edited']);
    $d3 = strtotime('now');
    if ($d1 > $d3) {
        $res['created'] = datetime_convert();
    }
    if ($d2 > $d3) {
        $res['edited'] = datetime_convert();
    }
    $rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner');
    if ($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']) {
        $res['owner-name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']);
    } elseif ($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']) {
        $res['owner-name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']);
    }
    if ($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']) {
        $res['owner-link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']);
    } elseif ($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']) {
        $res['owner-link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']);
    }
    if ($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
        $base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
        foreach ($base as $link) {
            if (!x($res, 'owner-avatar') || !$res['owner-avatar']) {
                if ($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
                    $res['owner-avatar'] = unxmlify($link['attribs']['']['href']);
                }
            }
        }
    }
    $rawgeo = $item->get_item_tags(NAMESPACE_GEORSS, 'point');
    if ($rawgeo) {
        $res['coord'] = unxmlify($rawgeo[0]['data']);
    }
    $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb');
    // select between supported verbs
    if ($rawverb) {
        $res['verb'] = unxmlify($rawverb[0]['data']);
    }
    // translate OStatus unfollow to activity streams if it happened to get selected
    if (x($res, 'verb') && $res['verb'] === 'http://ostatus.org/schema/1.0/unfollow') {
        $res['verb'] = ACTIVITY_UNFOLLOW;
    }
    $cats = $item->get_categories();
    if ($cats) {
        $tag_arr = array();
        foreach ($cats as $cat) {
            $term = $cat->get_term();
            if (!$term) {
                $term = $cat->get_label();
            }
            $scheme = $cat->get_scheme();
            if ($scheme && $term && stristr($scheme, 'X-DFRN:')) {
                $tag_arr[] = substr($scheme, 7, 1) . '[url=' . unxmlify(substr($scheme, 9)) . ']' . unxmlify($term) . '[/url]';
            } elseif ($term) {
                $tag_arr[] = notags(trim($term));
            }
        }
        $res['tag'] = implode(',', $tag_arr);
    }
    $attach = $item->get_enclosures();
    if ($attach) {
        $att_arr = array();
        foreach ($attach as $att) {
            $len = intval($att->get_length());
            $link = str_replace(array(',', '"'), array('%2D', '%22'), notags(trim(unxmlify($att->get_link()))));
            $title = str_replace(array(',', '"'), array('%2D', '%22'), notags(trim(unxmlify($att->get_title()))));
            $type = str_replace(array(',', '"'), array('%2D', '%22'), notags(trim(unxmlify($att->get_type()))));
            if (strpos($type, ';')) {
                $type = substr($type, 0, strpos($type, ';'));
            }
            if (!$link || strpos($link, 'http') !== 0) {
                continue;
            }
            if (!$title) {
                $title = ' ';
            }
            if (!$type) {
                $type = 'application/octet-stream';
            }
            $att_arr[] = '[attach]href="' . $link . '" length="' . $len . '" type="' . $type . '" title="' . $title . '"[/attach]';
        }
        $res['attach'] = implode(',', $att_arr);
    }
    $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
    if ($rawobj) {
        $res['object'] = '<object>' . "\n";
        $child = $rawobj[0]['child'];
        if ($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) {
            $res['object-type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'];
            $res['object'] .= '<type>' . $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'] . '</type>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) {
            $res['object'] .= '<id>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'] . '</id>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
            $res['object'] .= '<link>' . encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) . '</link>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']) {
            $res['object'] .= '<title>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'] . '</title>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
            $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
            if (!$body) {
                $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
            }
            // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
            $res['object'] .= '<orig>' . xmlify($body) . '</orig>' . "\n";
            if (strpos($body, '<') !== false || strpos($body, '>') !== false) {
                $body = html2bb_video($body);
                $config = HTMLPurifier_Config::createDefault();
                $config->set('Cache.DefinitionImpl', null);
                $purifier = new HTMLPurifier($config);
                $body = $purifier->purify($body);
                $body = html2bbcode($body);
            }
            $res['object'] .= '<content>' . $body . '</content>' . "\n";
        }
        $res['object'] .= '</object>' . "\n";
    }
    $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'target');
    if ($rawobj) {
        $res['target'] = '<target>' . "\n";
        $child = $rawobj[0]['child'];
        if ($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) {
            $res['target'] .= '<type>' . $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'] . '</type>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) {
            $res['target'] .= '<id>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'] . '</id>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
            $res['target'] .= '<link>' . encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) . '</link>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'data') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']) {
            $res['target'] .= '<title>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'] . '</title>' . "\n";
        }
        if (x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'data') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
            $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
            if (!$body) {
                $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
            }
            // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
            $res['target'] .= '<orig>' . xmlify($body) . '</orig>' . "\n";
            if (strpos($body, '<') !== false || strpos($body, '>') !== false) {
                $body = html2bb_video($body);
                $config = HTMLPurifier_Config::createDefault();
                $config->set('Cache.DefinitionImpl', null);
                $purifier = new HTMLPurifier($config);
                $body = $purifier->purify($body);
                $body = html2bbcode($body);
            }
            $res['target'] .= '<content>' . $body . '</content>' . "\n";
        }
        $res['target'] .= '</target>' . "\n";
    }
    $arr = array('feed' => $feed, 'item' => $item, 'result' => $res);
    call_hooks('parse_atom', $arr);
    return $res;
}