// default permissions - anonymous user
- $sql_extra = "
- AND `allow_cid` = ''
- AND `allow_gid` = ''
- AND `deny_cid` = ''
- AND `deny_gid` = ''
- ";
-
- if(strlen($owner_nick) && ! intval($owner_nick)) {
- $r = q("SELECT `uid`, `nickname`, `timezone` FROM `user` WHERE `nickname` = '%s' LIMIT 1",
- dbesc($owner_nick)
- );
- if(count($r)) {
- $owner_id = $r[0]['uid'];
- $owner_nick = $r[0]['nickname'];
- $owner_tz = $r[0]['timezone'];
- }
- }
-
- $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
- intval($owner_id)
- );
- if(count($r)) {
- $owner = $r[0];
- $owner['nickname'] = $owner_nick;
- }
- else
+ if(! strlen($owner_nick))
killme();
+ $sql_extra = " AND `allow_cid` = '' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = '' ";
- /**
- *
- * Determine the next birthday, but only if the birthday is published
- * in the default profile. We _could_ also look for a private profile that the
- * recipient can see, but somebody could get mad at us if they start getting
- * public birthday greetings when they haven't made this info public.
- *
- * Assuming we are able to publish this info, we are then going to convert
- * the start time from the owner's timezone to UTC.
- *
- * This will potentially solve the problem found with some social networks
- * where birthdays are converted to the viewer's timezone and salutations from
- * elsewhere in the world show up on the wrong day. We will convert it to the
- * viewer's timezone also, but first we are going to convert it from the birthday
- * person's timezone to GMT - so the viewer may find the birthday starting at
- * 6:00PM the day before, but that will correspond to midnight to the birthday person.
- *
- */
+ $r = q("SELECT `contact`.*, `user`.`uid` AS `user_uid`, `user`.`nickname`, `user`.`timezone`
+ FROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid`
+ WHERE `contact`.`self` = 1 AND `user`.`nickname` = '%s' LIMIT 1",
+ dbesc($owner_nick)
+ );
- $birthday = '';
+ if(! count($r))
+ killme();
- $p = q("SELECT `dob` FROM `profile` WHERE `is-default` = 1 AND `uid` = %d LIMIT 1",
- intval($owner_id)
- );
+ $owner = $r[0];
+ $owner_id = $owner['user_uid'];
+ $owner_nick = $owner['nickname'];
- if($p && count($p)) {
- $tmp_dob = substr($p[0]['dob'],5);
- if(intval($tmp_dob)) {
- $y = datetime_convert($owner_tz,$owner_tz,'now','Y');
- $bd = $y . '-' . $tmp_dob . ' 00:00';
- $t_dob = strtotime($bd);
- $now = strtotime(datetime_convert($owner_tz,$owner_tz,'now'));
- if($t_dob < $now)
- $bd = $y + 1 . '-' . $tmp_dob . ' 00:00';
- $birthday = datetime_convert($owner_tz,'UTC',$bd,ATOM_TIME);
- }
- }
+ $birthday = feed_birthday($owner_id,$owner['timezone']);
- if($dfrn_id && $dfrn_id != '*') {
+ if(strlen($dfrn_id)) {
$sql_extra = '';
switch($direction) {
);
if(! count($r))
- return false;
+ killme();
$contact = $r[0];
$groups = init_groups_visitor($contact['id']);
`contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
`contact`.`id` AS `contact-id`, `contact`.`uid` AS `contact-uid`
FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
- WHERE `item`.`uid` = %d AND `item`.`visible` = 1
+ WHERE `item`.`uid` = %d AND `item`.`visible` = 1 AND `item`.`parent` != 0
AND `item`.`wall` = 1 AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
AND ( `item`.`edited` > '%s' OR `item`.`changed` > '%s' )
$sql_extra
);
// Will check further below if this actually returned results.
- // We will provide an empty feed in any case.
+ // We will provide an empty feed if that is the case.
$items = $r;
$atom = '';
- $hub = get_config('system','huburl');
-
- $hubxml = '';
- if(strlen($hub)) {
- $hubs = explode(',', $hub);
- if(count($hubs)) {
- foreach($hubs as $h) {
- $h = trim($h);
- if(! strlen($h))
- continue;
- $hubxml .= '<link rel="hub" href="' . xmlify($h) . '" />' . "\n" ;
- }
- }
- }
-
- $salmon = '<link rel="salmon" href="' . xmlify($a->get_baseurl() . '/salmon/' . $owner_nick) . '" />' . "\n" ;
- $salmon .= '<link rel="http://salmon-protocol.org/ns/salmon-replies" href="' . xmlify($a->get_baseurl() . '/salmon/' . $owner_nick) . '" />' . "\n" ;
- $salmon .= '<link rel="http://salmon-protocol.org/ns/salmon-mention" href="' . xmlify($a->get_baseurl() . '/salmon/' . $owner_nick) . '" />' . "\n" ;
+ $hubxml = feed_hublinks();
+ $salmon = feed_salmonlinks($owner_nick);
$atom .= replace_macros($feed_template, array(
'$version' => xmlify(FRIENDIKA_VERSION),
// public feeds get html, our own nodes use bbcode
- if($dfrn_id === '*') {
+ if($dfrn_id === '') {
$type = 'html';
}
else {
if($item['object']) {
$o = '<as:object>' . "\r\n";
- $r = @simplexml_load_string($item['object']);
+ $r = parse_xml_string($item['object']);
if($r->type)
$o .= '<as:object-type>' . xmlify($r->type) . '</as:object-type>' . "\r\n";
if($r->id)
if($item['target']) {
$o = '<as:target>' . "\r\n";
- $r = @simplexml_load_string($item['target']);
+ $r = parse_xml_string($item['target']);
if($r->type)
$o .= '<as:object-type>' . xmlify($r->type) . '</as:object-type>' . "\r\n";
if($r->id)
$res = array();
$author = $item->get_author();
- $res['author-name'] = unxmlify($author->get_name());
- $res['author-link'] = unxmlify($author->get_link());
+ 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));
// look for a photo. We should check media size and find the best one,
// but for now let's just find any author photo
$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['realbody'] = true;
}
$maxlen = get_max_import_size();
// 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)) {
- if(! $have_real_body) {
- if((strpos($res['body'],'<')) || (strpos($res['body'],'>'))) {
+ $res['body'] = preg_replace('#<object[^>]+>.+?' . 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s',
+ '[youtube]$1[/youtube]', $res['body']);
- $res['body'] = preg_replace('#<object[^>]+>.+?' . 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s',
- '[youtube]$1[/youtube]', $res['body']);
+ $res['body'] = oembed_html2bbcode($res['body']);
- $res['body'] = oembed_html2bbcode($res['body']);
-
- $config = HTMLPurifier_Config::createDefault();
- $config->set('Cache.DefinitionImpl', null);
+ $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.
- // $config->set('HTML.Allowed', 'p,b,a[href],i');
+ // we shouldn't need a whitelist, because the bbcode converter
+ // will strip out any unsupported tags.
+ // $config->set('HTML.Allowed', 'p,b,a[href],i');
- $purifier = new HTMLPurifier($config);
- $res['body'] = $purifier->purify($res['body']);
+ $purifier = new HTMLPurifier($config);
+ $res['body'] = $purifier->purify($res['body']);
- $res['body'] = html2bbcode($res['body']);
- }
- else
- $res['body'] = escape_tags($res['body']);
+ $res['body'] = html2bbcode($res['body']);
}
-
$allow = $item->get_item_tags(NAMESPACE_DFRN,'comment-allow');
if($allow && $allow[0]['data'] == 1)
$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']);
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(',','%2D', notags(trim($att->get_link())));
+ $title = str_replace(',','%2D',notags(trim($att->get_title())));
+ $type = notags(trim($att->get_type()));
+ if((! $link) || (strpos($link,'http') !== 0))
+ continue;
+
+ if(! $title)
+ $title = ' ';
+ if(! $type)
+ $type = 'application/octet-stream';
+
+ // this isn't legal html - there is no size in an 'a' tag, remember to strip it before display
+
+ $att_arr[] = '<a href="' . $link . '" size="' . $len . '" type="' . $type . '">' . $title . '</a>';
+ }
+ $res['attach'] = implode(',', $att_arr);
+ }
$rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
$body = $rawobj[0]['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,'<')) || (strpos($body,'>'))) {
+ if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) {
$body = preg_replace('#<object[^>]+>.+?' . 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s',
'[youtube]$1[/youtube]', $body);
$body = $purifier->purify($body);
$body = html2bbcode($body);
}
- else
- $body = escape_tags($body);
$res['object'] .= '<content>' . $body . '</content>' . "\n";
}
$body = $rawobj[0]['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,'<')) || (strpos($body,'>'))) {
+ if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) {
$body = preg_replace('#<object[^>]+>.+?' . 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s',
'[youtube]$1[/youtube]', $body);
$body = $purifier->purify($body);
$body = html2bbcode($body);
}
- else
- $body = escape_tags($body);
$res['target'] .= '<content>' . $body . '</content>' . "\n";
}
return xmlify($o);
}
-function item_store($arr) {
+function item_store($arr,$force_parent = false) {
if($arr['gravity'])
$arr['gravity'] = intval($arr['gravity']);
if(! x($arr,'type'))
$arr['type'] = 'remote';
+
+ // Shouldn't happen but we want to make absolutely sure it doesn't leak from a plugin.
+
+ if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false))
+ $arr['body'] = strip_tags($arr['body']);
+
+
$arr['wall'] = ((x($arr,'wall')) ? intval($arr['wall']) : 0);
$arr['uri'] = ((x($arr,'uri')) ? notags(trim($arr['uri'])) : random_string());
$arr['author-name'] = ((x($arr,'author-name')) ? notags(trim($arr['author-name'])) : '');
$arr['object'] = ((x($arr,'object')) ? trim($arr['object']) : '');
$arr['target-type'] = ((x($arr,'target-type')) ? notags(trim($arr['target-type'])) : '');
$arr['target'] = ((x($arr,'target')) ? trim($arr['target']) : '');
+ $arr['plink'] = ((x($arr,'plink')) ? notags(trim($arr['plink'])) : '');
$arr['allow_cid'] = ((x($arr,'allow_cid')) ? trim($arr['allow_cid']) : '');
$arr['allow_gid'] = ((x($arr,'allow_gid')) ? trim($arr['allow_gid']) : '');
$arr['deny_cid'] = ((x($arr,'deny_cid')) ? trim($arr['deny_cid']) : '');
$arr['deny_gid'] = ((x($arr,'deny_gid')) ? trim($arr['deny_gid']) : '');
$arr['private'] = ((x($arr,'private')) ? intval($arr['private']) : 0 );
- $arr['body'] = ((x($arr,'body')) ? escape_tags(trim($arr['body'])) : '');
-
- // The content body may have been through a lot of filtering and transport escaping by now.
- // We don't want to skip any filters, however a side effect of all this filtering
- // is that ampersands and <> may have been double encoded, depending on which filter chain
- // they came through. The presence of $res['realbody'] means we have something encoded in a
- // transport safe manner at the source and does not require any filter corrections.
-
- if(x($arr,'realbody'))
- unset($arr['realbody']);
- else {
- $arr['body'] = str_replace(
- array('&amp;', '&gt;', '&lt;', '&quot;'),
- array('&' , '>' , '<', '"'),
- $arr['body']
- );
- }
+ $arr['body'] = ((x($arr,'body')) ? trim($arr['body']) : '');
+ $arr['tag'] = ((x($arr,'tag')) ? notags(trim($arr['tag'])) : '');
+ $arr['attach'] = ((x($arr,'attach')) ? notags(trim($arr['attach'])) : '');
if($arr['parent-uri'] === $arr['uri']) {
$parent_id = 0;
else {
// find the parent and snarf the item id and ACL's
+ // and anything else we need to inherit
$r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($arr['parent-uri']),
$arr['parent-uri'] = $r[0]['parent-uri'];
}
- $parent_id = $r[0]['id'];
- $allow_cid = $r[0]['allow_cid'];
- $allow_gid = $r[0]['allow_gid'];
- $deny_cid = $r[0]['deny_cid'];
- $deny_gid = $r[0]['deny_gid'];
+ $parent_id = $r[0]['id'];
+ $parent_deleted = $r[0]['deleted'];
+ $allow_cid = $r[0]['allow_cid'];
+ $allow_gid = $r[0]['allow_gid'];
+ $deny_cid = $r[0]['deny_cid'];
+ $deny_gid = $r[0]['deny_gid'];
+ $arr['wall'] = $r[0]['wall'];
}
else {
- logger('item_store: item parent was not found - ignoring item');
- return 0;
+
+ // Allow one to see reply tweets from status.net even when
+ // we don't have or can't see the original post.
+
+ if($force_parent) {
+ logger('item_store: $force_parent=true, reply converted to top-level post.');
+ $parent_id = 0;
+ $arr['thr-parent'] = $arr['parent-uri'];
+ $arr['parent-uri'] = $arr['uri'];
+ }
+ else {
+ logger('item_store: item parent was not found - ignoring item');
+ return 0;
+ }
}
}
return 0;
}
- if($arr['parent-uri'] === $arr['uri'])
+ if((! $parent_id) || ($arr['parent-uri'] === $arr['uri']))
$parent_id = $current_post;
-
- if(strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid))
+
+ if(strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid))
$private = 1;
else
$private = $arr['private'];
// Set parent id - and also make sure to inherit the parent's ACL's.
$r = q("UPDATE `item` SET `parent` = %d, `allow_cid` = '%s', `allow_gid` = '%s',
- `deny_cid` = '%s', `deny_gid` = '%s', `private` = %d WHERE `id` = %d LIMIT 1",
+ `deny_cid` = '%s', `deny_gid` = '%s', `private` = %d, `deleted` = %d WHERE `id` = %d LIMIT 1",
intval($parent_id),
dbesc($allow_cid),
dbesc($allow_gid),
dbesc($deny_cid),
dbesc($deny_gid),
intval($private),
+ intval($parent_deleted),
intval($current_post)
);
+ /**
+ * If this is now the last-child, force all _other_ children of this parent to *not* be last-child
+ */
+
+ if($arr['last-child']) {
+ $r = q("UPDATE `item` SET `last-child` = 0 WHERE `parent-uri` = '%s' AND `uid` = %d AND `id` != %d",
+ dbesc($arr['uri']),
+ intval($arr['uid']),
+ intval($current_post)
+ );
+ }
+
return $current_post;
}
$a = get_app();
- if((! strlen($contact['dfrn-id'])) && (! $contact['duplex']) && (! ($owner['page-flags'] == PAGE_COMMUNITY)))
+ if((! strlen($contact['issued-id'])) && (! $contact['duplex']) && (! ($owner['page-flags'] == PAGE_COMMUNITY)))
return 3;
$idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']);
if(! $rino_enable)
$rino = 0;
- $url = $contact['notify'] . '?dfrn_id=' . $idtosend . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . (($rino) ? '&rino=1' : '');
+ $url = $contact['notify'] . '&dfrn_id=' . $idtosend . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . (($rino) ? '&rino=1' : '');
logger('dfrn_deliver: ' . $url);
if(! $xml)
return 3;
- $res = simplexml_load_string($xml);
+ if(strpos($xml,'<?xml') === false) {
+ logger('dfrn_deliver: no valid XML returned');
+ logger('dfrn_deliver: returned XML: ' . $xml, LOGGER_DATA);
+ return 3;
+ }
+
+ $res = parse_xml_string($xml);
if((intval($res->status) != 0) || (! strlen($res->challenge)) || (! strlen($res->dfrn_id)))
return (($res->status) ? $res->status : 3);
$postvars = array();
$sent_dfrn_id = hex2bin((string) $res->dfrn_id);
$challenge = hex2bin((string) $res->challenge);
+ $dfrn_version = (float) (($res->dfrn_version) ? $res->dfrn_version : 2.0);
$rino_allowed = ((intval($res->rino) === 1) ? 1 : 0);
$final_dfrn_id = '';
- if(($contact['duplex'] && strlen($contact['prvkey'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) {
- openssl_private_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['prvkey']);
- openssl_private_decrypt($challenge,$postvars['challenge'],$contact['prvkey']);
- }
- else {
+ if(($contact['duplex'] && strlen($contact['pubkey'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) {
openssl_public_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['pubkey']);
openssl_public_decrypt($challenge,$postvars['challenge'],$contact['pubkey']);
}
+ else {
+ openssl_private_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['prvkey']);
+ openssl_private_decrypt($challenge,$postvars['challenge'],$contact['prvkey']);
+ }
$final_dfrn_id = substr($final_dfrn_id, 0, strpos($final_dfrn_id, '.'));
$postvars['data'] = $data;
logger('rino: sent key = ' . $key);
- if(($contact['duplex'] && strlen($contact['prvkey'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) {
- openssl_private_encrypt($key,$postvars['key'],$contact['prvkey']);
+
+ if($dfrn_version >= 2.1) {
+ if(($contact['duplex'] && strlen($contact['pubkey'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) {
+ openssl_public_encrypt($key,$postvars['key'],$contact['pubkey']);
+ }
+ else {
+ openssl_private_encrypt($key,$postvars['key'],$contact['prvkey']);
+ }
}
else {
- openssl_public_encrypt($key,$postvars['key'],$contact['pubkey']);
+ if(($contact['duplex'] && strlen($contact['prvkey'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) {
+ openssl_private_encrypt($key,$postvars['key'],$contact['prvkey']);
+ }
+ else {
+ openssl_public_encrypt($key,$postvars['key'],$contact['pubkey']);
+ }
}
logger('md5 rawkey ' . md5($postvars['key']));
if((! $curl_stat) || (! strlen($xml)))
return(-1); // timed out
- $res = simplexml_load_string($xml);
+
+ if(strpos($xml,'<?xml') === false) {
+ logger('dfrn_deliver: phase 2: no valid XML returned');
+ logger('dfrn_deliver: phase 2: returned XML: ' . $xml, LOGGER_DATA);
+ return 3;
+ }
+
+ $res = parse_xml_string($xml);
return $res->status;
}
-/*
+/**
*
* consume_feed - process atom feed and update anything/everything we might need to update
*
- * $xml = the (atom) feed to consume - no RSS spoken here, it might partially work since simplepie
- * handles both, but we don't claim it will work well, and are reasonably certain it won't.
+ * $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
*
*/
-function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0) {
+function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $secure_feed = false) {
require_once('simplepie/simplepie.inc');
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
}
- // Now process the feed
- if($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) {
+ // process any deleted entries
+ $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry');
+ if(is_array($del_entries) && count($del_entries)) {
+ foreach($del_entries as $dentry) {
$deleted = false;
-
- $rawdelete = $item->get_item_tags( NAMESPACE_TOMB, 'deleted-entry');
- if(isset($rawdelete[0]['attribs']['']['ref'])) {
- $uri = $rawthread[0]['attribs']['']['ref'];
+ if(isset($dentry['attribs']['']['ref'])) {
+ $uri = $dentry['attribs']['']['ref'];
$deleted = true;
- if(isset($rawdelete[0]['attribs']['']['when'])) {
- $when = $rawthread[0]['attribs']['']['when'];
+ if(isset($dentry['attribs']['']['when'])) {
+ $when = $dentry['attribs']['']['when'];
$when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s');
}
else
);
if(count($r)) {
$item = $r[0];
+
+ if(! $item['deleted'])
+ logger('consume_feed: deleting item ' . $item['id'] . ' uri=' . $item['uri'], LOGGER_DEBUG);
+
if($item['uri'] == $item['parent-uri']) {
$r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
`body` = '', `title` = ''
);
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 ",
+ 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'])
}
}
}
- continue;
}
+ }
+ }
+
+ // 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');
$parent_uri = $rawthread[0]['attribs']['']['ref'];
}
-
if(($is_reply) && is_array($contact)) {
-
+
// Have we seen it? If not, import it.
- $item_id = $item->get_id();
-
- $r = q("SELECT `uid`, `last-child`, `edited` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+ $item_id = $item->get_id();
+ $datarray = get_atom_elements($feed,$item);
+
+ $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($item_id),
intval($importer['uid'])
);
- // FIXME update content if 'updated' changes
+
+ // Update content if 'updated' changes
+
if(count($r)) {
+ if((x($datarray,'edited') !== false) && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
+ $r = q("UPDATE `item` SET `body` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+ dbesc($datarray['body']),
+ dbesc(datetime_convert('UTC','UTC',$datarray['edited'])),
+ dbesc($item_id),
+ intval($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",
}
continue;
}
- $datarray = get_atom_elements($feed,$item);
+ $force_parent = false;
if($contact['network'] === 'stat') {
+ $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",
$datarray['gravity'] = GRAVITY_LIKE;
}
- $r = item_store($datarray);
+ $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();
- $r = q("SELECT `uid`, `last-child`, `edited` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+ $item_id = $item->get_id();
+
+ $datarray = get_atom_elements($feed,$item);
+
+ $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((x($datarray,'edited') !== false) && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
+ $r = q("UPDATE `item` SET `body` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+ dbesc($datarray['body']),
+ dbesc(datetime_convert('UTC','UTC',$datarray['edited'])),
+ dbesc($item_id),
+ intval($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 LIMIT 1",
}
continue;
}
- $datarray = get_atom_elements($feed,$item);
if(activity_match($datarray['verb'],ACTIVITY_FOLLOW)) {
logger('consume-feed: New follower');
if(! is_array($contact))
return;
- if($contact['network'] === 'stat') {
+ if($contact['network'] === 'stat' || stristr($permalink,'twitter.com')) {
if(strlen($datarray['title']))
unset($datarray['title']);
$datarray['last-child'] = 1;
$o .= '<updated>' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '</updated>' . "\r\n";
$o .= '<dfrn:env>' . base64url_encode($item['body'], true) . '</dfrn:env>' . "\r\n";
$o .= '<content type="' . $type . '" >' . xmlify(($type === 'html') ? bbcode($item['body']) : $item['body']) . '</content>' . "\r\n";
- $o .= '<link rel="alternate" href="' . xmlify($a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id']) . '" />' . "\r\n";
+ $o .= '<link rel="alternate" type="text/html" href="' . xmlify($a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id']) . '" />' . "\r\n";
if($comment)
$o .= '<dfrn:comment-allow>' . intval($item['last-child']) . '</dfrn:comment-allow>' . "\r\n";
if(strlen($actarg))
$o .= $actarg;
+ $tags = item_getfeedtags($item);
+ if(count($tags)) {
+ foreach($tags as $t) {
+ $o .= '<category scheme="X-DFRN:' . xmlify($t[0]) . ':' . xmlify($t[1]) . '" term="' . xmlify($t[2]) . '" />' . "\r\n";
+ }
+ }
+
+ $o .= item_getfeedattach($item);
+
$mentioned = get_mentions($item);
if($mentioned)
$o .= $mentioned;
return $o;
}
+
+function item_getfeedtags($item) {
+ $ret = array();
+ $matches = false;
+ $cnt = preg_match_all('|\#\[url\=(.+?)\](.+?)\[\/url\]|',$item['tag'],$matches);
+ if($cnt) {
+ for($x = 0; $x < count($matches); $x ++) {
+ if($matches[1][$x])
+ $ret[] = array('#',$matches[1][$x], $matches[2][$x]);
+ }
+ }
+ $matches = false;
+ $cnt = preg_match_all('|\@\[url\=(.+?)\](.+?)\[\/url\]|',$item['tag'],$matches);
+ if($cnt) {
+ for($x = 0; $x < count($matches); $x ++) {
+ if($matches[1][$x])
+ $ret[] = array('#',$matches[1][$x], $matches[2][$x]);
+ }
+ }
+ return $ret;
+}
+
+function item_getfeedattach($item) {
+ $ret = '';
+ $arr = explode(',',$item['attach']);
+ if(count($arr)) {
+ foreach($arr as $r) {
+ $matches = false;
+ $cnt = preg_match('|\<a href=\"(.+?)\" size=\"(.+?)\" type=\"(.+?)\" >(.+?)</a>|',$r,$matches);
+ if($cnt) {
+ $ret .= '<link rel="enclosure" href="' . xmlify($matches[1]) . '" type="' . xmlify($matches[3]) . '" ';
+ if(intval($matches[2]))
+ $ret .= 'size="' . intval($matches[2]) . '" ';
+ if($matches[4] !== ' ')
+ $ret .= 'title="' . xmlify($matches[4]) . '" ';
+ $ret .= ' />' . "\r\n";
+ }
+ }
+ }
+ return $ret;
+}
+
+
+function item_expire($uid,$days) {
+
+ if((! $uid) || (! $days))
+ return;
+
+ $r = q("SELECT * FROM `item`
+ WHERE `uid` = %d
+ AND `created` < UTC_TIMESTAMP() - INTERVAL %d DAY
+ AND `id` = `parent`
+ AND `deleted` = 0",
+ intval($uid),
+ intval($days)
+ );
+
+ if(! count($r))
+ return;
+
+ logger('expire: # items=' . count($r) );
+
+ foreach($r as $item) {
+
+ // Only expire posts, not photos and photo comments
+
+ if(strlen($item['resource-id']))
+ continue;
+
+ $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' WHERE `id` = %d LIMIT 1",
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ intval($item['id'])
+ );
+
+ // kill the kids
+
+ $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ",
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ dbesc($item['parent-uri']),
+ intval($item['uid'])
+ );
+
+ }
+
+ proc_run('php',"include/notifier.php","expire","$uid");
+
+}
\ No newline at end of file