/**
*
* consume_feed - process atom feed and update anything/everything we might need to update
*
* $xml = the (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
*
* $importer = the contact_record (joined to user_record) of the local user who owns this relationship.
* It is this person's stuff that is going to be updated.
* $contact = the person who is sending us stuff. If not set, we MAY be processing a "follow" activity
* from an external network and MAY create an appropriate contact record. Otherwise, we MUST
* have a contact record.
* $hub = should we find a hub declation in the feed, pass it back to our calling process, who might (or
* might not) try and subscribe to it.
* $datedir sorts in reverse order
* $pass - by default ($pass = 0) we cannot guarantee that a parent item has been
* imported prior to its children being seen in the stream unless we are certain
* of how the feed is arranged/ordered.
* With $pass = 1, we only pull parent items out of the stream.
* With $pass = 2, we only pull children (comments/likes).
*
* So running this twice, first with pass 1 and then with pass 2 will do the right
* thing regardless of feed ordering. This won't be adequate in a fully-threaded
* model where comments can have sub-threads. That would require some massive sorting
* to get all the feed items into a mostly linear ordering, and might still require
* recursion.
*/
function consume_feed($xml, $importer, &$contact, &$hub, $datedir = 0, $pass = 0)
{
if ($contact['network'] === NETWORK_OSTATUS) {
if ($pass < 2) {
// Test - remove before flight
//$tempfile = tempnam(get_temppath(), "ostatus2");
//file_put_contents($tempfile, $xml);
logger("Consume OStatus messages ", LOGGER_DEBUG);
ostatus_import($xml, $importer, $contact, $hub);
}
return;
}
if ($contact['network'] === NETWORK_FEED) {
if ($pass < 2) {
logger("Consume feeds", LOGGER_DEBUG);
feed_import($xml, $importer, $contact, $hub);
}
return;
}
require_once 'library/simplepie/simplepie.inc';
require_once 'include/contact_selectors.php';
if (!strlen($xml)) {
logger('consume_feed: empty input');
return;
}
$feed = new SimplePie();
$feed->set_raw_data($xml);
if ($datedir) {
$feed->enable_order_by_date(true);
} else {
$feed->enable_order_by_date(false);
}
$feed->init();
if ($feed->error()) {
logger('consume_feed: Error parsing XML: ' . $feed->error());
}
$permalink = $feed->get_permalink();
// Check at the feed level for updated contact name and/or photo
$name_updated = '';
$new_name = '';
$photo_timestamp = '';
$photo_url = '';
$birthday = '';
$contact_updated = '';
$hubs = $feed->get_links('hub');
logger('consume_feed: hubs: ' . print_r($hubs, true), LOGGER_DATA);
if (count($hubs)) {
$hub = implode(',', $hubs);
}
$rawtags = $feed->get_feed_tags(NAMESPACE_DFRN, 'owner');
if (!$rawtags) {
$rawtags = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
}
if ($rawtags) {
$elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10];
if ($elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']) {
$name_updated = $elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated'];
$new_name = $elems['name'][0]['data'];
// Manually checking for changed contact names
if ($new_name != $contact['name'] and $new_name != "" and $name_updated <= $contact['name-date']) {
$name_updated = date("c");
$photo_timestamp = date("c");
}
}
if (x($elems, 'link') && $elems['link'][0]['attribs']['']['rel'] === 'photo' && $elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']) {
if ($photo_timestamp == "") {
$photo_timestamp = datetime_convert('UTC', 'UTC', $elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']);
}
$photo_url = $elems['link'][0]['attribs']['']['href'];
}
if (x($rawtags[0]['child'], NAMESPACE_DFRN) && x($rawtags[0]['child'][NAMESPACE_DFRN], 'birthday')) {
$birthday = datetime_convert('UTC', 'UTC', $rawtags[0]['child'][NAMESPACE_DFRN]['birthday'][0]['data']);
}
}
if (is_array($contact) && $photo_timestamp && strlen($photo_url) && $photo_timestamp > $contact['avatar-date']) {
logger('consume_feed: Updating photo for ' . $contact['name'] . ' from ' . $photo_url . ' uid: ' . $contact['uid']);
$contact_updated = $photo_timestamp;
require_once "include/Photo.php";
$photos = import_profile_photo($photo_url, $contact['uid'], $contact['id']);
q("UPDATE `contact` SET `avatar-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s'\n\t\t\tWHERE `uid` = %d AND `id` = %d AND NOT `self`", dbesc(datetime_convert()), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), intval($contact['uid']), intval($contact['id']));
}
if (is_array($contact) && $name_updated && strlen($new_name) && $name_updated > $contact['name-date']) {
if ($name_updated > $contact_updated) {
$contact_updated = $name_updated;
}
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($contact['uid']), intval($contact['id']));
$x = q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s' WHERE `uid` = %d AND `id` = %d AND `name` != '%s' AND NOT `self`", dbesc(notags(trim($new_name))), dbesc(datetime_convert()), intval($contact['uid']), intval($contact['id']), dbesc(notags(trim($new_name))));
// do our best to update the name on content items
if (count($r) and notags(trim($new_name)) != $r[0]['name']) {
q("UPDATE `item` SET `author-name` = '%s' WHERE `author-name` = '%s' AND `author-link` = '%s' AND `uid` = %d AND `author-name` != '%s'", dbesc(notags(trim($new_name))), dbesc($r[0]['name']), dbesc($r[0]['url']), intval($contact['uid']), dbesc(notags(trim($new_name))));
}
}
if ($contact_updated and $new_name and $photo_url) {
poco_check($contact['url'], $new_name, NETWORK_DFRN, $photo_url, "", "", "", "", "", $contact_updated, 2, $contact['id'], $contact['uid']);
}
if (strlen($birthday)) {
if (substr($birthday, 0, 4) != $contact['bdyear']) {
logger('consume_feed: updating birthday: ' . $birthday);
/**
*
* Add new birthday event for this person
*
* $bdtext is just a readable placeholder in case the event is shared
* with others. We will replace it during presentation to our $importer
* to contain a sparkle link and perhaps a photo.
*
*/
$bdtext = sprintf(t('%s\'s birthday'), $contact['name']);
$bdtext2 = sprintf(t('Happy Birthday %s'), ' [url=' . $contact['url'] . ']' . $contact['name'] . '[/url]');
$r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`)\n\t\t\t\tVALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($contact['uid']), intval($contact['id']), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert('UTC', 'UTC', $birthday)), dbesc(datetime_convert('UTC', 'UTC', $birthday . ' + 1 day ')), dbesc($bdtext), dbesc($bdtext2), dbesc('birthday'));
// update bdyear
q("UPDATE `contact` SET `bdyear` = '%s' WHERE `uid` = %d AND `id` = %d", dbesc(substr($birthday, 0, 4)), intval($contact['uid']), intval($contact['id']));
// This function is called twice without reloading the contact
// Make sure we only create one event. This is why &$contact
// is a reference var in this function
$contact['bdyear'] = substr($birthday, 0, 4);
}
}
$community_page = 0;
$rawtags = $feed->get_feed_tags(NAMESPACE_DFRN, 'community');
if ($rawtags) {
$community_page = intval($rawtags[0]['data']);
}
if (is_array($contact) && intval($contact['forum']) != $community_page) {
q("update contact set forum = %d where id = %d", intval($community_page), intval($contact['id']));
$contact['forum'] = (string) $community_page;
}
// process any deleted entries
$del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry');
if (is_array($del_entries) && count($del_entries) && $pass != 2) {
foreach ($del_entries as $dentry) {
$deleted = false;
if (isset($dentry['attribs']['']['ref'])) {
$uri = $dentry['attribs']['']['ref'];
$deleted = true;
if (isset($dentry['attribs']['']['when'])) {
$when = $dentry['attribs']['']['when'];
$when = datetime_convert('UTC', 'UTC', $when, 'Y-m-d H:i:s');
} else {
$when = datetime_convert('UTC', 'UTC', 'now', 'Y-m-d H:i:s');
}
}
if ($deleted && is_array($contact)) {
$r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN `contact` on `item`.`contact-id` = `contact`.`id`\n\t\t\t\t\tWHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", dbesc($uri), intval($importer['uid']), intval($contact['id']));
if (count($r)) {
$item = $r[0];
if (!$item['deleted']) {
logger('consume_feed: deleting item ' . $item['id'] . ' uri=' . $item['uri'], LOGGER_DEBUG);
}
if ($item['object-type'] === ACTIVITY_OBJ_EVENT) {
logger("Deleting event " . $item['event-id'], LOGGER_DEBUG);
event_delete($item['event-id']);
}
if ($item['verb'] === ACTIVITY_TAG && $item['object-type'] === ACTIVITY_OBJ_TAGTERM) {
$xo = parse_xml_string($item['object'], false);
$xt = parse_xml_string($item['target'], false);
if ($xt->type === ACTIVITY_OBJ_NOTE) {
$i = q("select * from `item` where uri = '%s' and uid = %d limit 1", dbesc($xt->id), intval($importer['importer_uid']));
if (count($i)) {
// For tags, the owner cannot remove the tag on the author's copy of the post.
$owner_remove = $item['contact-id'] == $i[0]['contact-id'] ? true : false;
$author_remove = $item['origin'] && $item['self'] ? true : false;
$author_copy = $item['origin'] ? true : false;
if ($owner_remove && $author_copy) {
continue;
}
if ($author_remove || $owner_remove) {
$tags = explode(',', $i[0]['tag']);
$newtags = array();
if (count($tags)) {
foreach ($tags as $tag) {
if (trim($tag) !== trim($xo->body)) {
$newtags[] = trim($tag);
}
}
}
q("update item set tag = '%s' where id = %d", dbesc(implode(',', $newtags)), intval($i[0]['id']));
create_tags_from_item($i[0]['id']);
}
}
}
}
if ($item['uri'] == $item['parent-uri']) {
$r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',\n\t\t\t\t\t\t\t`body` = '', `title` = ''\n\t\t\t\t\t\t\tWHERE `parent-uri` = '%s' AND `uid` = %d", dbesc($when), dbesc(datetime_convert()), dbesc($item['uri']), intval($importer['uid']));
create_tags_from_itemuri($item['uri'], $importer['uid']);
create_files_from_itemuri($item['uri'], $importer['uid']);
update_thread_uri($item['uri'], $importer['uid']);
} else {
$r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',\n\t\t\t\t\t\t\t`body` = '', `title` = ''\n\t\t\t\t\t\t\tWHERE `uri` = '%s' AND `uid` = %d", dbesc($when), dbesc(datetime_convert()), dbesc($uri), intval($importer['uid']));
create_tags_from_itemuri($uri, $importer['uid']);
create_files_from_itemuri($uri, $importer['uid']);
if ($item['last-child']) {
// ensure that last-child is set in case the comment that had it just got wiped.
q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", dbesc(datetime_convert()), dbesc($item['parent-uri']), intval($item['uid']));
// who is the last child now?
$r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `moderated` = 0 AND `uid` = %d\n\t\t\t\t\t\t\t\tORDER BY `created` DESC LIMIT 1", dbesc($item['parent-uri']), intval($importer['uid']));
if (count($r)) {
q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d", intval($r[0]['id']));
}
}
}
}
}
}
}
// Now process the feed
if ($feed->get_item_quantity()) {
logger('consume_feed: feed item count = ' . $feed->get_item_quantity());
// in inverse date order
if ($datedir) {
$items = array_reverse($feed->get_items());
} else {
$items = $feed->get_items();
}
foreach ($items as $item) {
$is_reply = false;
$item_id = $item->get_id();
$rawthread = $item->get_item_tags(NAMESPACE_THREAD, 'in-reply-to');
if (isset($rawthread[0]['attribs']['']['ref'])) {
$is_reply = true;
$parent_uri = $rawthread[0]['attribs']['']['ref'];
}
if ($is_reply && is_array($contact)) {
if ($pass == 1) {
continue;
}
// not allowed to post
if ($contact['rel'] == CONTACT_IS_FOLLOWER) {
continue;
}
// Have we seen it? If not, import it.
$item_id = $item->get_id();
$datarray = get_atom_elements($feed, $item, $contact);
if (!x($datarray, 'author-name') && $contact['network'] != NETWORK_DFRN) {
$datarray['author-name'] = $contact['name'];
}
if (!x($datarray, 'author-link') && $contact['network'] != NETWORK_DFRN) {
$datarray['author-link'] = $contact['url'];
}
if (!x($datarray, 'author-avatar') && $contact['network'] != NETWORK_DFRN) {
$datarray['author-avatar'] = $contact['thumb'];
}
if (!x($datarray, 'author-name') || !x($datarray, 'author-link')) {
logger('consume_feed: no author information! ' . print_r($datarray, true));
continue;
}
$force_parent = false;
if ($contact['network'] === NETWORK_OSTATUS || stristr($contact['url'], 'twitter.com')) {
if ($contact['network'] === NETWORK_OSTATUS) {
$force_parent = true;
}
if (strlen($datarray['title'])) {
unset($datarray['title']);
}
$r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc(datetime_convert()), dbesc($parent_uri), intval($importer['uid']));
$datarray['last-child'] = 1;
update_thread_uri($parent_uri, $importer['uid']);
}
$r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['uid']));
// Update content if 'updated' changes
if (count($r)) {
if (edited_timestamp_is_newer($r[0], $datarray)) {
// do not accept (ignore) an earlier edit than one we currently have.
if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
continue;
}
$r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc(datetime_convert()), dbesc($item_id), intval($importer['uid']));
create_tags_from_itemuri($item_id, $importer['uid']);
update_thread_uri($item_id, $importer['uid']);
}
// update last-child if it changes
$allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
if ($allow && $allow[0]['data'] != $r[0]['last-child']) {
$r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc(datetime_convert()), dbesc($parent_uri), intval($importer['uid']));
$r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id), intval($importer['uid']));
update_thread_uri($item_id, $importer['uid']);
}
continue;
}
if ($contact['network'] === NETWORK_FEED || !strlen($contact['notify'])) {
// one way feed - no remote comment ability
$datarray['last-child'] = 0;
}
$datarray['parent-uri'] = $parent_uri;
$datarray['uid'] = $importer['uid'];
$datarray['contact-id'] = $contact['id'];
if ($datarray['verb'] === ACTIVITY_LIKE || $datarray['verb'] === ACTIVITY_DISLIKE || $datarray['verb'] === ACTIVITY_ATTEND || $datarray['verb'] === ACTIVITY_ATTENDNO || $datarray['verb'] === ACTIVITY_ATTENDMAYBE) {
$datarray['type'] = 'activity';
$datarray['gravity'] = GRAVITY_LIKE;
// only one like or dislike per person
// splitted into two queries for performance issues
$r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 and (`parent-uri` = '%s') limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($parent_uri));
if ($r && count($r)) {
continue;
}
$r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 and (`thr-parent` = '%s') limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($parent_uri));
if ($r && count($r)) {
continue;
}
}
if ($datarray['verb'] === ACTIVITY_TAG && $datarray['object-type'] === ACTIVITY_OBJ_TAGTERM) {
$xo = parse_xml_string($datarray['object'], false);
$xt = parse_xml_string($datarray['target'], false);
if ($xt->type == ACTIVITY_OBJ_NOTE) {
$r = q("select * from item where `uri` = '%s' AND `uid` = %d limit 1", dbesc($xt->id), intval($importer['importer_uid']));
if (!count($r)) {
continue;
}
// extract tag, if not duplicate, add to parent item
if ($xo->id && $xo->content) {
$newtag = '#[url=' . $xo->id . ']' . $xo->content . '[/url]';
if (!stristr($r[0]['tag'], $newtag)) {
q("UPDATE item SET tag = '%s' WHERE id = %d", dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . $newtag), intval($r[0]['id']));
create_tags_from_item($r[0]['id']);
}
}
}
}
$r = item_store($datarray, $force_parent);
continue;
} else {
// Head post of a conversation. Have we seen it? If not, import it.
$item_id = $item->get_id();
$datarray = get_atom_elements($feed, $item, $contact);
if (is_array($contact)) {
if (!x($datarray, 'author-name') && $contact['network'] != NETWORK_DFRN) {
$datarray['author-name'] = $contact['name'];
}
if (!x($datarray, 'author-link') && $contact['network'] != NETWORK_DFRN) {
$datarray['author-link'] = $contact['url'];
}
if (!x($datarray, 'author-avatar') && $contact['network'] != NETWORK_DFRN) {
$datarray['author-avatar'] = $contact['thumb'];
}
}
if (!x($datarray, 'author-name') || !x($datarray, 'author-link')) {
logger('consume_feed: no author information! ' . print_r($datarray, true));
continue;
}
// special handling for events
if (x($datarray, 'object-type') && $datarray['object-type'] === ACTIVITY_OBJ_EVENT) {
$ev = bbtoevent($datarray['body']);
if ((x($ev, 'desc') || x($ev, 'summary')) && x($ev, 'start')) {
$ev['uid'] = $importer['uid'];
$ev['uri'] = $item_id;
$ev['edited'] = $datarray['edited'];
$ev['private'] = $datarray['private'];
$ev['guid'] = $datarray['guid'];
if (is_array($contact)) {
$ev['cid'] = $contact['id'];
}
$r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['uid']));
if (count($r)) {
$ev['id'] = $r[0]['id'];
}
$xyz = event_store($ev);
continue;
}
}
if ($contact['network'] === NETWORK_OSTATUS || stristr($contact['url'], 'twitter.com')) {
if (strlen($datarray['title'])) {
unset($datarray['title']);
}
$datarray['last-child'] = 1;
}
$r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['uid']));
// Update content if 'updated' changes
if (count($r)) {
if (edited_timestamp_is_newer($r[0], $datarray)) {
// do not accept (ignore) an earlier edit than one we currently have.
if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
continue;
}
$r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc(datetime_convert()), dbesc($item_id), intval($importer['uid']));
create_tags_from_itemuri($item_id, $importer['uid']);
update_thread_uri($item_id, $importer['uid']);
}
// update last-child if it changes
$allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
if ($allow && $allow[0]['data'] != $r[0]['last-child']) {
$r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id), intval($importer['uid']));
update_thread_uri($item_id, $importer['uid']);
}
continue;
}
if (activity_match($datarray['verb'], ACTIVITY_FOLLOW)) {
logger('consume-feed: New follower');
new_follower($importer, $contact, $datarray, $item);
return;
}
if (activity_match($datarray['verb'], ACTIVITY_UNFOLLOW)) {
lose_follower($importer, $contact, $datarray, $item);
return;
}
if (activity_match($datarray['verb'], ACTIVITY_REQ_FRIEND)) {
logger('consume-feed: New friend request');
new_follower($importer, $contact, $datarray, $item, true);
return;
}
if (activity_match($datarray['verb'], ACTIVITY_UNFRIEND)) {
lose_sharer($importer, $contact, $datarray, $item);
return;
}
if (!is_array($contact)) {
return;
}
if ($contact['network'] === NETWORK_FEED || !strlen($contact['notify'])) {
// one way feed - no remote comment ability
$datarray['last-child'] = 0;
}
if ($contact['network'] === NETWORK_FEED) {
$datarray['private'] = 2;
}
$datarray['parent-uri'] = $item_id;
$datarray['uid'] = $importer['uid'];
$datarray['contact-id'] = $contact['id'];
if (!link_compare($datarray['owner-link'], $contact['url'])) {
// The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery,
// but otherwise there's a possible data mixup on the sender's system.
// the tgroup delivery code called from item_store will correct it if it's a forum,
// but we're going to unconditionally correct it here so that the post will always be owned by our contact.
logger('consume_feed: Correcting item owner.', LOGGER_DEBUG);
$datarray['owner-name'] = $contact['name'];
$datarray['owner-link'] = $contact['url'];
$datarray['owner-avatar'] = $contact['thumb'];
}
// We've allowed "followers" to reach this point so we can decide if they are
// posting an @-tag delivery, which followers are allowed to do for certain
// page types. Now that we've parsed the post, let's check if it is legit. Otherwise ignore it.
if ($contact['rel'] == CONTACT_IS_FOLLOWER && !tgroup_check($importer['uid'], $datarray)) {
continue;
}
// This is my contact on another system, but it's really me.
// Turn this into a wall post.
$notify = item_is_remote_self($contact, $datarray);
$r = item_store($datarray, false, $notify);
logger('Stored - Contact ' . $contact['url'] . ' Notify ' . $notify . ' return ' . $r . ' Item ' . print_r($datarray, true), LOGGER_DEBUG);
continue;
}
}
}
}