2016-05-13 03:21:04 +00:00
< ? php
/**
2017-04-03 20:08:32 +00:00
* @ brief Return an Atom feed for channel .
*
* @ see get_feed_for ()
2016-05-13 03:21:04 +00:00
*
* @ param array $channel
2017-04-03 20:08:32 +00:00
* @ param array $params associative array which configures the feed
* @ return string with an atom feed
2016-05-13 03:21:04 +00:00
*/
function get_public_feed ( $channel , $params ) {
2017-04-03 20:08:32 +00:00
/* $type = 'xml' ;
2016-05-13 03:21:04 +00:00
$begin = NULL_DATE ;
$end = '' ;
$start = 0 ;
$records = 40 ;
$direction = 'desc' ;
$pages = 0 ;
2017-04-03 20:08:32 +00:00
*/
2016-05-13 03:21:04 +00:00
if ( ! $params )
2017-04-26 03:48:38 +00:00
$params = [];
2016-05-13 03:21:04 +00:00
2017-04-26 03:48:38 +00:00
$params [ 'type' ] = (( x ( $params , 'type' )) ? $params [ 'type' ] : 'xml' );
$params [ 'begin' ] = (( x ( $params , 'begin' )) ? $params [ 'begin' ] : NULL_DATE );
$params [ 'end' ] = (( x ( $params , 'end' )) ? $params [ 'end' ] : datetime_convert ( 'UTC' , 'UTC' , 'now' ));
$params [ 'start' ] = (( x ( $params , 'start' )) ? $params [ 'start' ] : 0 );
$params [ 'records' ] = (( x ( $params , 'records' )) ? $params [ 'records' ] : 40 );
$params [ 'direction' ] = (( x ( $params , 'direction' )) ? $params [ 'direction' ] : 'desc' );
$params [ 'pages' ] = (( x ( $params , 'pages' )) ? intval ( $params [ 'pages' ]) : 0 );
$params [ 'top' ] = (( x ( $params , 'top' )) ? intval ( $params [ 'top' ]) : 0 );
$params [ 'cat' ] = (( x ( $params , 'cat' )) ? $params [ 'cat' ] : '' );
$params [ 'compat' ] = (( x ( $params , 'compat' )) ? intval ( $params [ 'compat' ]) : 0 );
2016-05-13 03:21:04 +00:00
switch ( $params [ 'type' ]) {
case 'json' :
header ( " Content-type: application/atom+json " );
break ;
case 'xml' :
default :
header ( " Content-type: application/atom+xml " );
break ;
}
return get_feed_for ( $channel , get_observer_hash (), $params );
}
/**
2017-04-03 20:08:32 +00:00
* @ brief Create an atom feed for $channel from template .
2016-05-13 03:21:04 +00:00
*
* @ param array $channel
2017-04-03 20:08:32 +00:00
* @ param string $observer_hash xchan_hash from observer
2016-05-13 03:21:04 +00:00
* @ param array $params
2017-04-03 20:08:32 +00:00
* @ return string with an atom feed
2016-05-13 03:21:04 +00:00
*/
2017-04-26 03:48:38 +00:00
2016-05-13 03:21:04 +00:00
function get_feed_for ( $channel , $observer_hash , $params ) {
2017-04-21 04:31:44 +00:00
if ( ! $channel )
2016-05-13 03:21:04 +00:00
http_status_exit ( 401 );
if ( $params [ 'pages' ]) {
if ( ! perm_is_allowed ( $channel [ 'channel_id' ], $observer_hash , 'view_pages' ))
http_status_exit ( 403 );
} else {
if ( ! perm_is_allowed ( $channel [ 'channel_id' ], $observer_hash , 'view_stream' ))
http_status_exit ( 403 );
}
2017-04-26 03:48:38 +00:00
// logger('params: ' . print_r($params,true));
2016-05-13 03:21:04 +00:00
$feed_template = get_markup_template ( 'atom_feed.tpl' );
$atom = '' ;
2017-04-26 03:48:38 +00:00
$feed_author = '' ;
if ( intval ( $params [ 'compat' ]) === 1 ) {
2017-05-12 00:39:26 +00:00
$feed_author = atom_render_author ( 'author' , $channel );
2017-04-26 03:48:38 +00:00
}
2017-05-12 00:39:26 +00:00
$owner = atom_render_author ( 'zot:owner' , $channel );
2016-05-13 03:21:04 +00:00
$atom .= replace_macros ( $feed_template , array (
2016-05-21 05:52:47 +00:00
'$version' => xmlify ( Zotlabs\Lib\System :: get_project_version ()),
'$red' => xmlify ( Zotlabs\Lib\System :: get_platform_name ()),
2016-05-13 03:21:04 +00:00
'$feed_id' => xmlify ( $channel [ 'xchan_url' ]),
'$feed_title' => xmlify ( $channel [ 'channel_name' ]),
2017-04-03 20:08:32 +00:00
'$feed_updated' => xmlify ( datetime_convert ( 'UTC' , 'UTC' , 'now' , ATOM_TIME )),
2017-04-26 03:48:38 +00:00
'$author' => $feed_author ,
2017-05-12 00:39:26 +00:00
'$owner' => $owner ,
2016-05-13 03:21:04 +00:00
'$name' => xmlify ( $channel [ 'channel_name' ]),
'$profile_page' => xmlify ( $channel [ 'xchan_url' ]),
'$mimephoto' => xmlify ( $channel [ 'xchan_photo_mimetype' ]),
'$photo' => xmlify ( $channel [ 'xchan_photo_l' ]),
'$thumb' => xmlify ( $channel [ 'xchan_photo_m' ]),
'$picdate' => '' ,
'$uridate' => '' ,
'$namdate' => '' ,
'$birthday' => '' ,
'$community' => '' ,
));
2017-04-21 04:25:37 +00:00
$x = [ 'xml' => $atom , 'channel' => $channel , 'observer_hash' => $observer_hash , 'params' => $params ];
call_hooks ( 'atom_feed_top' , $x );
$atom = $x [ 'xml' ];
// a much simpler interface
2016-05-13 03:21:04 +00:00
call_hooks ( 'atom_feed' , $atom );
2017-04-21 04:25:37 +00:00
2017-04-26 03:48:38 +00:00
$items = items_fetch (
[
'wall' => '1' ,
'datequery' => $params [ 'end' ],
'datequery2' => $params [ 'begin' ],
'start' => intval ( $params [ 'start' ]),
'records' => intval ( $params [ 'records' ]),
'direction' => dbesc ( $params [ 'direction' ]),
'pages' => $params [ 'pages' ],
'order' => dbesc ( 'post' ),
'top' => $params [ 'top' ],
'cat' => $params [ 'cat' ],
'compat' => $params [ 'compat' ]
], $channel , $observer_hash , CLIENT_MODE_NORMAL , App :: $module
);
2016-05-13 03:21:04 +00:00
if ( $items ) {
$type = 'html' ;
foreach ( $items as $item ) {
if ( $item [ 'item_private' ])
continue ;
/** @BUG $owner is undefined in this call */
2017-06-05 02:09:05 +00:00
$atom .= atom_entry ( $item , $type , null , $owner , true , '' , $params [ 'compat' ]);
2016-05-13 03:21:04 +00:00
}
}
call_hooks ( 'atom_feed_end' , $atom );
$atom .= '</feed>' . " \r \n " ;
return $atom ;
}
/**
2017-04-03 20:08:32 +00:00
* @ brief Return the verb for an item , or fall back to ACTIVITY_POST .
2016-05-13 03:21:04 +00:00
*
* @ param array $item an associative array with
2017-04-03 20:08:32 +00:00
* * \e string \b verb
2016-05-13 03:21:04 +00:00
* @ return string item ' s verb if set , default ACTIVITY_POST see boot . php
*/
function construct_verb ( $item ) {
if ( $item [ 'verb' ])
return $item [ 'verb' ];
return ACTIVITY_POST ;
}
function construct_activity_object ( $item ) {
2016-06-02 04:48:54 +00:00
if ( $item [ 'obj' ]) {
2016-05-13 03:21:04 +00:00
$o = '<as:object>' . " \r \n " ;
2016-06-02 04:48:54 +00:00
$r = json_decode ( $item [ 'obj' ], false );
2016-05-13 03:21:04 +00:00
if ( ! $r )
return '' ;
if ( $r -> type )
$o .= '<as:obj_type>' . xmlify ( $r -> type ) . '</as:obj_type>' . " \r \n " ;
if ( $r -> id )
$o .= '<id>' . xmlify ( $r -> id ) . '</id>' . " \r \n " ;
if ( $r -> title )
$o .= '<title>' . xmlify ( $r -> title ) . '</title>' . " \r \n " ;
if ( $r -> links ) {
/** @FIXME!! */
if ( substr ( $r -> link , 0 , 1 ) === '<' ) {
$r -> link = preg_replace ( '/\<link(.*?)\"\>/' , '<link$1"/>' , $r -> link );
$o .= $r -> link ;
}
else
$o .= '<link rel="alternate" type="text/html" href="' . xmlify ( $r -> link ) . '" />' . " \r \n " ;
}
2017-04-03 20:08:32 +00:00
if ( $r -> content ) {
2016-05-13 03:21:04 +00:00
$o .= '<content type="html" >' . xmlify ( bbcode ( $r -> content )) . '</content>' . " \r \n " ;
2017-04-03 20:08:32 +00:00
}
2016-05-13 03:21:04 +00:00
$o .= '</as:object>' . " \r \n " ;
2017-04-03 20:08:32 +00:00
2016-05-13 03:21:04 +00:00
return $o ;
}
return '' ;
}
function construct_activity_target ( $item ) {
if ( $item [ 'target' ]) {
$o = '<as:target>' . " \r \n " ;
$r = json_decode ( $item [ 'target' ], false );
if ( ! $r )
return '' ;
if ( $r -> type )
$o .= '<as:obj_type>' . xmlify ( $r -> type ) . '</as:obj_type>' . " \r \n " ;
if ( $r -> id )
$o .= '<id>' . xmlify ( $r -> id ) . '</id>' . " \r \n " ;
if ( $r -> title )
$o .= '<title>' . xmlify ( $r -> title ) . '</title>' . " \r \n " ;
if ( $r -> links ) {
/** @FIXME !!! */
if ( substr ( $r -> link , 0 , 1 ) === '<' ) {
if ( strstr ( $r -> link , '&' ) && ( ! strstr ( $r -> link , '&' )))
$r -> link = str_replace ( '&' , '&' , $r -> link );
$r -> link = preg_replace ( '/\<link(.*?)\"\>/' , '<link$1"/>' , $r -> link );
$o .= $r -> link ;
}
else
$o .= '<link rel="alternate" type="text/html" href="' . xmlify ( $r -> link ) . '" />' . " \r \n " ;
}
if ( $r -> content )
$o .= '<content type="html" >' . xmlify ( bbcode ( $r -> content )) . '</content>' . " \r \n " ;
$o .= '</as:target>' . " \r \n " ;
return $o ;
}
return '' ;
}
/**
2017-04-03 20:08:32 +00:00
* @ brief Return an array with a parsed atom item .
*
* @ param SimplePie $feed
2016-05-13 03:21:04 +00:00
* @ param array $item
* @ param [ out ] array $author
2017-04-03 20:08:32 +00:00
* @ return array Associative array with the parsed item data
2016-05-13 03:21:04 +00:00
*/
function get_atom_elements ( $feed , $item , & $author ) {
2017-04-03 20:08:32 +00:00
require_once ( 'include/html2bbcode.php' );
2016-05-13 03:21:04 +00:00
$res = array ();
$found_author = $item -> get_author ();
if ( $found_author ) {
2017-06-30 05:38:43 +00:00
if ( $rawauthor ) {
if ( $rawauthor [ 0 ][ 'child' ][ NAMESPACE_POCO ][ 'displayName' ][ 0 ][ 'data' ])
$author [ 'full_name' ] = unxmlify ( $rawauthor [ 0 ][ 'child' ][ NAMESPACE_POCO ][ 'displayName' ][ 0 ][ 'data' ]);
}
2016-05-13 03:21:04 +00:00
$author [ 'author_name' ] = unxmlify ( $found_author -> get_name ());
$author [ 'author_link' ] = unxmlify ( $found_author -> get_link ());
$author [ 'author_is_feed' ] = false ;
2017-06-30 05:38:43 +00:00
$rawauthor = $feed -> get_feed_tags ( SIMPLEPIE_NAMESPACE_ATOM_10 , 'author' );
logger ( 'rawauthor: ' . print_r ( $rawauthor , true ));
2016-05-13 03:21:04 +00:00
}
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 );
2017-06-15 03:20:18 +00:00
$res [ 'mid' ] = normalise_id ( unxmlify ( $item -> get_id ()));
2016-05-13 03:21:04 +00:00
$res [ 'title' ] = unxmlify ( $item -> get_title ());
$res [ 'body' ] = unxmlify ( $item -> get_content ());
$res [ 'plink' ] = unxmlify ( $item -> get_link ( 0 ));
$res [ 'item_rss' ] = 1 ;
2017-06-14 02:52:16 +00:00
$summary = unxmlify ( $item -> get_description ( true ));
2016-05-13 03:21:04 +00:00
// removing the content of the title if its identically to the body
// This helps with auto generated titles e.g. from tumblr
2017-04-03 20:08:32 +00:00
if ( title_is_body ( $res [ 'title' ], $res [ 'body' ]))
2016-05-13 03:21:04 +00:00
$res [ 'title' ] = " " ;
if ( $res [ 'plink' ])
$base_url = implode ( '/' , array_slice ( explode ( '/' , $res [ 'plink' ]), 0 , 3 ));
else
$base_url = '' ;
2017-06-13 02:17:50 +00:00
$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' );
2017-04-12 03:17:22 +00:00
$rawverb = $item -> get_item_tags ( NAMESPACE_ACTIVITY , 'verb' );
2016-05-13 03:21:04 +00:00
2017-04-12 03:17:22 +00:00
// select between supported verbs
if ( $rawverb ) {
$res [ 'verb' ] = unxmlify ( $rawverb [ 0 ][ 'data' ]);
2016-05-13 03:21:04 +00:00
}
2017-06-13 02:17:50 +00:00
// look for a photo. We should check media size and find the best one,
// but for now let's just find any author photo
2017-04-12 03:17:22 +00:00
2017-06-13 02:17:50 +00:00
$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' ]);
2017-04-12 03:17:22 +00:00
}
2017-06-13 02:17:50 +00:00
}
}
$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' ]);
2017-04-12 03:17:22 +00:00
}
}
2016-05-13 03:21:04 +00:00
}
}
2017-06-13 02:17:50 +00:00
// 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
2016-05-13 03:21:04 +00:00
2017-06-17 02:30:02 +00:00
2017-06-13 02:17:50 +00:00
if (( ! ( x ( $author , 'author_link' ))) || ( ! ( x ( $author , 'author_photo' )))) {
$rawauthor = $feed -> get_feed_tags ( SIMPLEPIE_NAMESPACE_ATOM_10 , 'author' );
2016-05-13 03:21:04 +00:00
if ( $rawauthor && $rawauthor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'link' ]) {
$base = $rawauthor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'link' ];
foreach ( $base as $link ) {
2017-06-13 02:17:50 +00:00
if ( $link [ 'attribs' ][ '' ][ 'rel' ] === 'alternate' && ( ! $author [ 'author_link' ])) {
$author [ 'author_link' ] = unxmlify ( $link [ 'attribs' ][ '' ][ 'href' ]);
$author [ 'author_is_feed' ] = true ;
}
if ( ! $author [ 'author_photo' ]) {
2016-05-13 03:21:04 +00:00
if ( $link [ 'attribs' ][ '' ][ 'rel' ] === 'photo' || $link [ 'attribs' ][ '' ][ 'rel' ] === 'avatar' )
$author [ 'author_photo' ] = unxmlify ( $link [ 'attribs' ][ '' ][ 'href' ]);
}
}
}
2017-06-13 02:17:50 +00:00
$rawactor = $feed -> get_feed_tags ( NAMESPACE_ACTIVITY , 'subject' );
2016-05-13 03:21:04 +00:00
2017-06-13 02:17:50 +00:00
if ( $rawactor && activity_match ( $rawactor [ 0 ][ 'child' ][ NAMESPACE_ACTIVITY ][ 'obj_type' ][ 0 ][ 'data' ], ACTIVITY_OBJ_PERSON )) {
2016-05-13 03:21:04 +00:00
$base = $rawactor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'link' ];
2017-06-13 02:17:50 +00:00
2016-05-13 03:21:04 +00:00
if ( $base && count ( $base )) {
foreach ( $base as $link ) {
if ( $link [ 'attribs' ][ '' ][ 'rel' ] === 'alternate' && ( ! $res [ 'author_link' ]))
$author [ 'author_link' ] = unxmlify ( $link [ 'attribs' ][ '' ][ 'href' ]);
2017-06-13 02:17:50 +00:00
if ( ! ( x ( $author , 'author_photo' ))) {
2016-05-13 03:21:04 +00:00
if ( $link [ 'attribs' ][ '' ][ 'rel' ] === 'avatar' || $link [ 'attribs' ][ '' ][ 'rel' ] === 'photo' )
$author [ 'author_photo' ] = unxmlify ( $link [ 'attribs' ][ '' ][ 'href' ]);
}
}
}
}
}
2017-06-13 04:58:40 +00:00
$rawcnv = $item -> get_item_tags ( NAMESPACE_OSTATUS , 'conversation' );
if ( $rawcnv ) {
2017-07-05 05:05:17 +00:00
// new style
2017-06-15 03:20:18 +00:00
$ostatus_conversation = normalise_id ( unxmlify ( $rawcnv [ 0 ][ 'attribs' ][ '' ][ 'ref' ]));
2017-07-05 05:05:17 +00:00
if ( ! $ostatus_conversation ) {
// old style
$ostatus_conversation = normalise_id ( unxmlify ( $rawcnv [ 0 ][ 'data' ]));
}
if ( $ostatus_conversation ) {
set_iconfig ( $res , 'ostatus' , 'conversation' , $ostatus_conversation , true );
logger ( 'ostatus_conversation: ' . $ostatus_conversation , LOGGER_DATA , LOG_INFO );
}
2017-06-13 04:58:40 +00:00
}
$ostatus_protocol = (( $ostatus_conversation ) ? true : false );
2017-06-07 05:49:45 +00:00
$mastodon = (( $item -> get_item_tags ( 'http://mastodon.social/schema/1.0' , 'scope' )) ? true : false );
2017-07-15 22:49:10 +00:00
if ( $mastodon ) {
2017-06-07 05:49:45 +00:00
$ostatus_protocol = true ;
2017-07-15 22:49:10 +00:00
if (( $mastodon [ 0 ][ 'data' ]) && ( $mastodon [ 0 ][ 'data' ] !== 'public' ))
$res [ 'item_private' ] = 1 ;
}
2017-01-07 20:47:19 +00:00
2017-04-03 20:08:32 +00:00
$apps = $item -> get_item_tags ( NAMESPACE_STATUSNET , 'notice_info' );
2016-05-13 03:21:04 +00:00
if ( $apps && $apps [ 0 ][ 'attribs' ][ '' ][ 'source' ]) {
$res [ 'app' ] = strip_tags ( unxmlify ( $apps [ 0 ][ 'attribs' ][ '' ][ 'source' ]));
}
2017-06-28 03:07:48 +00:00
if ( $ostatus_protocol ) {
// 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 ;
}
// And OStatus 'favorite' is pretty much what we call 'like' on other networks
if (( x ( $res , 'verb' )) && ( $res [ 'verb' ] === ACTIVITY_FAVORITE )) {
$res [ 'verb' ] = ACTIVITY_LIKE ;
}
}
2016-05-13 03:21:04 +00:00
/*
* 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' );
2017-01-07 20:47:19 +00:00
if ( ! $rawenv )
2017-04-03 20:08:32 +00:00
$rawenv = $item -> get_item_tags ( NAMESPACE_ZOT , 'source' );
2016-05-13 03:21:04 +00:00
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' ]);
}
2017-01-04 19:47:08 +00:00
2017-04-03 20:08:32 +00:00
// strip title and don't apply "title-in-body" if the feed involved
2017-01-07 20:47:19 +00:00
// uses the OStatus stack. We need a more generalised way for the calling
2017-04-03 20:08:32 +00:00
// function to specify this behaviour or for plugins to alter it.
2017-01-04 19:47:08 +00:00
2017-01-07 20:47:19 +00:00
if ( $ostatus_protocol ) {
2017-01-04 19:47:08 +00:00
$res [ 'title' ] = '' ;
}
elseif ( $res [ 'plink' ] && $res [ 'title' ]) {
2016-05-13 03:21:04 +00:00
$res [ 'body' ] = '#^[url=' . $res [ 'plink' ] . ']' . $res [ 'title' ] . '[/url]' . " \n \n " . $res [ 'body' ];
$terms = array ();
$terms [] = array (
'otype' => TERM_OBJ_POST ,
2016-07-05 23:24:45 +00:00
'ttype' => TERM_BOOKMARK ,
2016-05-13 03:21:04 +00:00
'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 ,
2016-07-05 23:24:45 +00:00
'ttype' => TERM_BOOKMARK ,
2016-05-13 03:21:04 +00:00
'url' => $res [ 'plink' ],
'term' => $res [ 'plink' ],
);
}
2017-06-14 02:52:16 +00:00
// turn Mastodon content warning into a #nsfw hashtag
if ( $mastodon && $summary ) {
2017-07-13 00:07:31 +00:00
$res [ 'body' ] .= " \n \n #ContentWarning \n " ;
2017-06-14 02:52:16 +00:00
}
2017-04-03 20:08:32 +00:00
$private = $item -> get_item_tags ( NAMESPACE_DFRN , 'private' );
2016-05-13 03:21:04 +00:00
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' ]);
// 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 )
2017-04-03 20:08:32 +00:00
$rawowner = $item -> get_item_tags ( NAMESPACE_ZOT , 'owner' );
2016-05-13 03:21:04 +00:00
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' ]);
}
}
}
2017-04-03 20:08:32 +00:00
$rawgeo = $item -> get_item_tags ( NAMESPACE_GEORSS , 'point' );
2016-05-13 03:21:04 +00:00
if ( $rawgeo )
$res [ 'coord' ] = unxmlify ( $rawgeo [ 0 ][ 'data' ]);
$cats = $item -> get_categories ();
if ( $cats ) {
if ( is_null ( $terms ))
$terms = array ();
2017-04-03 20:08:32 +00:00
2016-05-13 03:21:04 +00:00
foreach ( $cats as $cat ) {
$term = $cat -> get_term ();
if ( ! $term )
$term = $cat -> get_label ();
2017-04-03 20:08:32 +00:00
2016-05-13 03:21:04 +00:00
$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 ,
2017-04-03 20:08:32 +00:00
'ttype' => $termtype ,
2016-05-13 03:21:04 +00:00
'url' => $termurl ,
'term' => $termterm ,
);
}
}
}
if ( ! is_null ( $terms ))
$res [ 'term' ] = $terms ;
$attach = $item -> get_enclosures ();
if ( $attach ) {
2017-06-13 02:17:50 +00:00
2016-05-13 03:21:04 +00:00
$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' ;
2017-06-27 06:06:15 +00:00
if ( $ostatus_protocol ) {
if (( strpos ( $type , 'image' ) === 0 ) && ( strpos ( $res [ 'body' ], ']' . $link . '[/img]' ) === false ) && ( strpos ( $link , 'http' ) === 0 )) {
$res [ 'body' ] .= " \n \n " . '[img]' . $link . '[/img]' ;
}
if (( strpos ( $type , 'video' ) === 0 ) && ( strpos ( $res [ 'body' ], ']' . $link . '[/video]' ) === false ) && ( strpos ( $link , 'http' ) === 0 )) {
$res [ 'body' ] .= " \n \n " . '[video]' . $link . '[/video]' ;
}
if (( strpos ( $type , 'audio' ) === 0 ) && ( strpos ( $res [ 'body' ], ']' . $link . '[/audio]' ) === false ) && ( strpos ( $link , 'http' ) === 0 )) {
$res [ 'body' ] .= " \n \n " . '[audio]' . $link . '[/audio]' ;
}
2017-06-17 02:30:02 +00:00
}
2016-05-13 03:21:04 +00:00
$res [ 'attach' ][] = array ( 'href' => $link , 'length' => $len , 'type' => $type , 'title' => $title );
}
}
2017-06-13 02:17:50 +00:00
2016-05-13 03:21:04 +00:00
$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 ( $child [ NAMESPACE_ACTIVITY ][ 'object-type' ][ 0 ][ 'data' ]) {
$res [ 'obj_type' ] = $child [ NAMESPACE_ACTIVITY ][ 'object-type' ][ 0 ][ 'data' ];
$obj [ 'type' ] = $child [ NAMESPACE_ACTIVITY ][ 'object-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' ];
2017-04-03 20:08:32 +00:00
2016-05-13 03:21:04 +00:00
// 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 ;
}
2016-06-02 04:48:54 +00:00
$res [ 'obj' ] = $obj ;
2016-05-13 03:21:04 +00:00
}
$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 ( $child [ NAMESPACE_ACTIVITY ][ 'object-type' ][ 0 ][ 'data' ]) {
$res [ 'tgt_type' ] = $child [ NAMESPACE_ACTIVITY ][ 'object-type' ][ 0 ][ 'data' ];
$obj [ 'type' ] = $child [ NAMESPACE_ACTIVITY ][ 'object-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 ;
}
2017-06-17 02:30:02 +00:00
if ( array_key_exists ( 'verb' , $res ) && $res [ 'verb' ] === ACTIVITY_SHARE
2017-06-27 00:07:59 +00:00
&& array_key_exists ( 'obj_type' , $res ) && in_array ( $res [ 'obj_type' ], [ ACTIVITY_OBJ_NOTE , ACTIVITY_OBJ_COMMENT , ACTIVITY_OBJ_ACTIVITY ] )) {
2017-06-13 02:17:50 +00:00
feed_get_reshare ( $res , $item );
}
2017-04-03 20:08:32 +00:00
// build array to pass to hook
$arr = [
'feed' => $feed ,
'item' => $item ,
'author' => $author ,
'result' => $res
];
2016-05-13 03:21:04 +00:00
call_hooks ( 'parse_atom' , $arr );
2017-04-03 20:08:32 +00:00
logger ( 'author: ' . print_r ( $arr [ 'author' ], true ), LOGGER_DATA );
logger ( 'result: ' . print_r ( $arr [ 'result' ], true ), LOGGER_DATA );
2016-05-13 03:21:04 +00:00
2017-01-07 20:47:19 +00:00
return $arr [ 'result' ];
2016-05-13 03:21:04 +00:00
}
2017-06-13 02:17:50 +00:00
function feed_get_reshare ( & $res , $item ) {
$share = [];
// For Mastodon shares ("boosts"), we need to parse the original author information
// from the activity:object -> author structure
$rawobj = $item -> get_item_tags ( NAMESPACE_ACTIVITY , 'object' );
if ( $rawobj ) {
2017-06-17 02:30:02 +00:00
$rawauthor = $rawobj [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'author' ];
2017-06-13 02:17:50 +00:00
if ( $rawauthor && $rawauthor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'name' ]) {
2017-06-17 02:30:02 +00:00
$share [ 'author' ] = unxmlify ( $rawauthor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'name' ][ 0 ][ 'data' ]);
2017-06-13 02:17:50 +00:00
}
if ( $rawauthor && $rawauthor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'uri' ]) {
2017-06-17 02:30:02 +00:00
$share [ 'profile' ] = unxmlify ( $rawauthor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'uri' ][ 0 ][ 'data' ]);
2017-06-13 02:17:50 +00:00
}
if ( $rawauthor && $rawauthor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'link' ]) {
$base = $rawauthor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'link' ];
foreach ( $base as $link ) {
if ( ! ( array_key_exists ( 'avatar' , $share ) && $share [ 'avatar' ])) {
if ( $link [ 'attribs' ][ '' ][ 'rel' ] === 'photo' || $link [ 'attribs' ][ '' ][ 'rel' ] === 'avatar' )
$share [ 'avatar' ] = unxmlify ( $link [ 'attribs' ][ '' ][ 'href' ]);
}
}
}
if ( ! $share [ 'author' ])
$share [ 'author' ] = t ( 'unknown' );
if ( ! $share [ 'avatar' ])
$share [ 'avatar' ] = z_root () . '/' . get_default_profile_photo ( 80 );
if ( ! $share [ 'profile' ])
$share [ 'profile' ] = z_root ();
$child = $rawobj [ 0 ][ 'child' ];
if ( x ( $child [ SIMPLEPIE_NAMESPACE_ATOM_10 ], 'link' ) && $child [ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'link' ])
2017-06-17 02:30:02 +00:00
$share [ 'links' ] = encode_rel_links ( $child [ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'link' ]);
$rawcreated = $rawobj [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'published' ];
2017-06-13 02:17:50 +00:00
if ( $rawcreated )
$share [ 'created' ] = unxmlify ( $rawcreated [ 0 ][ 'data' ]);
else
$share [ 'created' ] = $res [ 'created' ];
if ( x ( $child [ SIMPLEPIE_NAMESPACE_ATOM_10 ], 'id' ) && $child [ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'id' ][ 0 ][ 'data' ])
$share [ 'message_id' ] = unxmlify ( $child [ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'id' ][ 0 ][ 'data' ]);
if ( x ( $child [ SIMPLEPIE_NAMESPACE_ATOM_10 ], 'content' ) && $child [ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'content' ][ 0 ][ 'data' ]) {
$body = unxmlify ( $child [ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'content' ][ 0 ][ 'data' ]);
if ( ! $body )
$body = unxmlify ( $child [ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'summary' ][ 0 ][ 'data' ]);
if (( strpos ( $body , '<' ) !== false ) || ( strpos ( $body , '>' ) !== false )) {
$body = purify_html ( $body );
$body = html2bbcode ( $body );
}
}
2017-06-17 02:30:02 +00:00
$attach = $share [ 'links' ];
2017-06-13 02:17:50 +00:00
if ( $attach ) {
foreach ( $attach as $att ) {
2017-06-17 02:30:02 +00:00
if ( $att [ 'rel' ] === 'alternate' ) {
$share [ 'alternate' ] = str_replace ( array ( ',' , '"' ), array ( '%2D' , '%22' ), notags ( trim ( unxmlify ( $att [ 'href' ]))));
continue ;
}
if ( $att [ 'rel' ] !== 'enclosure' )
continue ;
$len = intval ( $att [ 'length' ]);
$link = str_replace ( array ( ',' , '"' ), array ( '%2D' , '%22' ), notags ( trim ( unxmlify ( $att [ 'href' ]))));
$title = str_replace ( array ( ',' , '"' ), array ( '%2D' , '%22' ), notags ( trim ( unxmlify ( $att [ 'title' ]))));
$type = str_replace ( array ( ',' , '"' ), array ( '%2D' , '%22' ), notags ( trim ( unxmlify ( $att [ 'type' ]))));
2017-06-13 02:17:50 +00:00
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' ;
2017-06-27 06:06:15 +00:00
if (( strpos ( $type , 'image' ) === 0 ) && ( strpos ( $body , ']' . $link . '[/img]' ) === false ) && ( strpos ( $link , 'http' ) === 0 )) {
2017-06-13 02:17:50 +00:00
$body .= " \n \n " . '[img]' . $link . '[/img]' ;
}
2017-06-27 06:06:15 +00:00
if (( strpos ( $type , 'video' ) === 0 ) && ( strpos ( $body , ']' . $link . '[/video]' ) === false ) && ( strpos ( $link , 'http' ) === 0 )) {
$body .= " \n \n " . '[video]' . $link . '[/video]' ;
}
if (( strpos ( $type , 'audio' ) === 0 ) && ( strpos ( $body , ']' . $link . '[/audio]' ) === false ) && ( strpos ( $link , 'http' ) === 0 )) {
$body .= " \n \n " . '[audio]' . $link . '[/audio]' ;
}
2017-06-13 02:17:50 +00:00
}
}
$res [ 'body' ] = " [share author=' " . urlencode ( $share [ 'author' ]) .
" ' profile=' " . $share [ 'profile' ] .
" ' avatar=' " . $share [ 'avatar' ] .
2017-06-17 02:30:02 +00:00
" ' link=' " . $share [ 'alternate' ] .
2017-06-13 02:17:50 +00:00
" ' posted=' " . $share [ 'created' ] .
" ' message_id=' " . $share [ 'message_id' ] . " '] " ;
2017-06-17 02:30:02 +00:00
$res [ 'body' ] .= $body ;
$res [ 'body' ] .= " [/share] " ;
2017-06-13 02:17:50 +00:00
}
}
2017-04-03 20:08:32 +00:00
/**
* @ brief Encodes SimplePie_Item link arrays .
*
* @ param array $links Array with SimplePie_Item link tags
* @ return array
*/
2016-05-13 03:21:04 +00:00
function encode_rel_links ( $links ) {
$o = array ();
if ( ! (( is_array ( $links )) && ( count ( $links ))))
return $o ;
foreach ( $links as $link ) {
$l = array ();
if ( $link [ 'attribs' ][ '' ][ 'rel' ])
$l [ 'rel' ] = $link [ 'attribs' ][ '' ][ 'rel' ];
2017-06-17 02:30:02 +00:00
if ( $link [ 'attribs' ][ '' ][ 'length' ])
$l [ 'length' ] = $link [ 'attribs' ][ '' ][ 'length' ];
if ( $link [ 'attribs' ][ '' ][ 'title' ])
$l [ 'title' ] = $link [ 'attribs' ][ '' ][ 'title' ];
2016-05-13 03:21:04 +00:00
if ( $link [ 'attribs' ][ '' ][ 'type' ])
$l [ 'type' ] = $link [ 'attribs' ][ '' ][ 'type' ];
if ( $link [ 'attribs' ][ '' ][ 'href' ])
$l [ 'href' ] = $link [ 'attribs' ][ '' ][ 'href' ];
2017-04-03 20:08:32 +00:00
if ( ( x ( $link [ 'attribs' ], NAMESPACE_MEDIA )) && $link [ 'attribs' ][ NAMESPACE_MEDIA ][ 'width' ])
2016-05-13 03:21:04 +00:00
$l [ 'width' ] = $link [ 'attribs' ][ NAMESPACE_MEDIA ][ 'width' ];
2017-04-03 20:08:32 +00:00
if ( ( x ( $link [ 'attribs' ], NAMESPACE_MEDIA )) && $link [ 'attribs' ][ NAMESPACE_MEDIA ][ 'height' ])
2016-05-13 03:21:04 +00:00
$l [ 'height' ] = $link [ 'attribs' ][ NAMESPACE_MEDIA ][ 'height' ];
if ( $l )
$o [] = $l ;
}
2017-04-03 20:08:32 +00:00
2016-05-13 03:21:04 +00:00
return $o ;
}
/**
* @ brief Process atom feed and update anything / everything we might need to update .
*
2017-04-03 20:08:32 +00:00
* @ param string $xml
2016-05-13 03:21:04 +00:00
* The ( atom ) feed to consume - RSS isn ' t as fully supported but may work for simple feeds .
* @ param $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 .
2017-05-04 22:23:57 +00:00
* @ param [ in , out ] array $contact
2016-05-13 03:21:04 +00:00
* 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 .
* @ param int $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 , $pass = 0 ) {
if ( ! strlen ( $xml )) {
2017-04-03 20:08:32 +00:00
logger ( 'Empty input' );
2016-05-13 03:21:04 +00:00
return ;
}
2017-04-03 20:08:32 +00:00
$sys_expire = intval ( get_config ( 'system' , 'default_expire_days' ));
2016-05-13 03:21:04 +00:00
$chn_expire = intval ( $importer [ 'channel_expire_days' ]);
$expire_days = $sys_expire ;
if (( $chn_expire != 0 ) && ( $chn_expire < $sys_expire ))
$expire_days = $chn_expire ;
$feed = new SimplePie ();
$feed -> set_raw_data ( $xml );
2017-04-03 20:08:32 +00:00
// We can preserve iframes because we will strip them in the purifier after
// checking for supported video sources.
$strip_htmltags = $feed -> strip_htmltags ;
array_splice ( $strip_htmltags , array_search ( 'iframe' , $strip_htmltags ), 1 );
$feed -> strip_htmltags ( $strip_htmltags );
2016-05-13 03:21:04 +00:00
$feed -> init ();
if ( $feed -> error ())
2017-04-03 20:08:32 +00:00
logger ( 'Error parsing XML: ' . $feed -> error ());
2016-05-13 03:21:04 +00:00
$permalink = $feed -> get_permalink ();
// Check at the feed level for updated contact name and/or photo
// 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' ])) {
2017-01-10 22:25:11 +00:00
$mid = normalise_id ( $dentry [ 'attribs' ][ '' ][ 'ref' ]);
2016-05-13 03:21:04 +00:00
$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 * from item where mid = '%s' and author_xchan = '%s' and uid = %d limit 1 " ,
2017-01-06 21:25:57 +00:00
dbesc ( $mid ),
2016-05-13 03:21:04 +00:00
dbesc ( $contact [ 'xchan_hash' ]),
intval ( $importer [ 'channel_id' ])
);
if ( $r ) {
$item = $r [ 0 ];
if ( ! intval ( $item [ 'item_deleted' ])) {
2017-04-03 20:08:32 +00:00
logger ( 'deleting item ' . $item [ 'id' ] . ' mid=' . $item [ 'mid' ], LOGGER_DEBUG );
2016-05-13 03:21:04 +00:00
drop_item ( $item [ 'id' ], false );
}
}
}
}
}
// Now process the feed
if ( $feed -> get_item_quantity ()) {
2017-04-03 20:08:32 +00:00
logger ( 'feed item count = ' . $feed -> get_item_quantity (), LOGGER_DEBUG );
2016-05-13 03:21:04 +00:00
$items = $feed -> get_items ();
foreach ( $items as $item ) {
$is_reply = false ;
2017-06-28 02:20:13 +00:00
$parent_link = '' ;
2016-05-13 03:21:04 +00:00
2017-04-03 20:08:32 +00:00
logger ( 'processing ' . $item -> get_id (), LOGGER_DEBUG );
2016-05-13 03:21:04 +00:00
$rawthread = $item -> get_item_tags ( NAMESPACE_THREAD , 'in-reply-to' );
if ( isset ( $rawthread [ 0 ][ 'attribs' ][ '' ][ 'ref' ])) {
$is_reply = true ;
2017-01-10 22:25:11 +00:00
$parent_mid = normalise_id ( $rawthread [ 0 ][ 'attribs' ][ '' ][ 'ref' ]);
2016-05-13 03:21:04 +00:00
}
2017-06-28 02:20:13 +00:00
if ( isset ( $rawthread [ 0 ][ 'attribs' ][ '' ][ 'href' ])) {
$parent_link = $rawthread [ 0 ][ 'attribs' ][ '' ][ 'href' ];
}
2016-05-13 03:21:04 +00:00
2017-07-10 00:08:25 +00:00
logger ( 'in-reply-to: ' . $parent_mid , LOGGER_DEBUG );
2016-05-13 03:21:04 +00:00
if ( $is_reply ) {
if ( $pass == 1 )
continue ;
// Have we seen it? If not, import it.
$author = array ();
$datarray = get_atom_elements ( $feed , $item , $author );
2017-06-15 03:20:18 +00:00
if ( ! $datarray [ 'mid' ])
continue ;
2017-03-04 19:56:59 +00:00
2017-07-15 22:49:10 +00:00
// A Mastodon privacy tag has been found. We cannot send private comments
// through the OStatus protocol, so block commenting.
if ( array_key_exists ( 'item_private' , $datarray ) && intval ( $datarray [ 'item_private' ])) {
$datarray [ 'public_policy' ] = 'specific' ;
$datarray [ 'comment_policy' ] = 'none' ;
}
2016-05-13 03:21:04 +00:00
if ( $contact [ 'xchan_network' ] === 'rss' ) {
$datarray [ 'public_policy' ] = 'specific' ;
$datarray [ 'comment_policy' ] = 'none' ;
}
2017-07-17 05:51:36 +00:00
// if we have everything but a photo, provide the default profile photo
if ( $author [ 'author_name' ] && $author [ 'author_link' ] && ( ! $author [ 'author_photo' ]))
$author [ 'author_photo' ] = z_root () . '/' . get_default_profile_photo ( 80 );
2016-05-13 03:21:04 +00:00
if (( ! x ( $author , 'author_name' )) || ( $author [ 'author_is_feed' ]))
$author [ 'author_name' ] = $contact [ 'xchan_name' ];
if (( ! x ( $author , 'author_link' )) || ( $author [ 'author_is_feed' ]))
$author [ 'author_link' ] = $contact [ 'xchan_url' ];
if (( ! x ( $author , 'author_photo' )) || ( $author [ 'author_is_feed' ]))
$author [ 'author_photo' ] = $contact [ 'xchan_photo_m' ];
$datarray [ 'author_xchan' ] = '' ;
if ( $author [ 'author_link' ] != $contact [ 'xchan_url' ]) {
2017-06-30 05:38:43 +00:00
$name = '' ;
if ( $author [ 'full_name' ]) {
$name = $author [ 'full_name' ];
if ( $author [ 'author_name' ])
$name .= ' (' . $author [ 'author_name' ] . ')' ;
}
else {
$name = $author [ 'author_name' ];
}
$x = import_author_unknown ( array ( 'name' => $name , 'url' => $author [ 'author_link' ], 'photo' => array ( 'src' => $author [ 'author_photo' ])));
2016-05-13 03:21:04 +00:00
if ( $x )
$datarray [ 'author_xchan' ] = $x ;
}
if ( ! $datarray [ 'author_xchan' ])
$datarray [ 'author_xchan' ] = $contact [ 'xchan_hash' ];
$datarray [ 'owner_xchan' ] = $contact [ 'xchan_hash' ];
$r = q ( " SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1 " ,
2017-06-15 03:20:18 +00:00
dbesc ( $datarray [ 'mid' ]),
2016-05-13 03:21:04 +00:00
intval ( $importer [ 'channel_id' ])
);
// Update content if 'updated' changes
if ( $r ) {
if (( x ( $datarray , 'edited' ) !== false )
&& ( datetime_convert ( 'UTC' , 'UTC' , $datarray [ 'edited' ]) !== $r [ 0 ][ 'edited' ])) {
// do not accept (ignore) an earlier edit than one we currently have.
if ( datetime_convert ( 'UTC' , 'UTC' , $datarray [ 'edited' ]) < $r [ 0 ][ 'edited' ])
continue ;
update_feed_item ( $importer [ 'channel_id' ], $datarray );
}
continue ;
}
2017-06-14 01:06:45 +00:00
$pmid = '' ;
$conv_id = get_iconfig ( $datarray , 'ostatus' , 'conversation' );
2017-06-15 03:20:18 +00:00
// match conversations - first try ostatus:conversation
// next try thr:in_reply_to
2017-06-14 01:06:45 +00:00
if ( $conv_id ) {
2017-07-12 00:31:57 +00:00
logger ( 'find_parent: conversation_id: ' . $conv_id , LOGGER_DEBUG );
2017-06-14 01:06:45 +00:00
$c = q ( " select parent_mid from item left join iconfig on item.id = iconfig.iid where iconfig.cat = 'ostatus' and iconfig.k = 'conversation' and iconfig.v = '%s' and item.uid = %d order by item.id limit 1 " ,
dbesc ( $conv_id ),
intval ( $importer [ 'channel_id' ])
);
if ( $c ) {
2017-07-10 00:08:25 +00:00
logger ( 'find_parent: matched conversation: ' . $conv_id , LOGGER_DEBUG );
2017-06-28 02:20:13 +00:00
$pmid = $c [ 0 ][ 'parent_mid' ];
2017-06-14 01:06:45 +00:00
$datarray [ 'parent_mid' ] = $pmid ;
}
2017-06-13 04:12:14 +00:00
}
2017-06-15 03:20:18 +00:00
if ( ! $pmid ) {
2017-06-14 23:06:25 +00:00
$x = q ( " select parent_mid from item where mid = '%s' and uid = %d limit 1 " ,
2017-06-14 01:06:45 +00:00
dbesc ( $parent_mid ),
intval ( $importer [ 'channel_id' ])
);
if ( $x ) {
2017-07-10 00:08:25 +00:00
logger ( 'find_parent: matched in-reply-to: ' . $parent_mid , LOGGER_DEBUG );
2017-06-14 23:06:25 +00:00
$pmid = $x [ 0 ][ 'parent_mid' ];
2017-06-14 01:06:45 +00:00
$datarray [ 'parent_mid' ] = $pmid ;
}
}
2017-06-28 02:20:13 +00:00
if (( ! $pmid ) && $parent_link !== '' ) {
$f = feed_conversation_fetch ( $importer , $contact , $parent_link );
if ( $f ) {
2017-06-29 03:07:53 +00:00
// check both potential conversation parents again
if ( $conv_id ) {
$c = q ( " select parent_mid from item left join iconfig on item.id = iconfig.iid where iconfig.cat = 'ostatus' and iconfig.k = 'conversation' and iconfig.v = '%s' and item.uid = %d order by item.id limit 1 " ,
dbesc ( $conv_id ),
intval ( $importer [ 'channel_id' ])
);
if ( $c ) {
$pmid = $c [ 0 ][ 'parent_mid' ];
$datarray [ 'parent_mid' ] = $pmid ;
}
}
if ( ! $pmid ) {
$x = q ( " select parent_mid from item where mid = '%s' and uid = %d limit 1 " ,
dbesc ( $parent_mid ),
intval ( $importer [ 'channel_id' ])
);
2017-06-28 02:20:13 +00:00
2017-06-29 03:07:53 +00:00
if ( $x ) {
$pmid = $x [ 0 ][ 'parent_mid' ];
$datarray [ 'parent_mid' ] = $pmid ;
}
2017-06-28 02:20:13 +00:00
}
}
2017-06-30 07:50:57 +00:00
// the conversation parent might just be the post we are trying to import.
// check existence again in case it was just delivered.
$r = q ( " SELECT id FROM item WHERE mid = '%s' AND uid = %d LIMIT 1 " ,
dbesc ( $datarray [ 'mid' ]),
intval ( $importer [ 'channel_id' ])
);
if ( $r ) {
continue ;
}
2017-06-28 02:20:13 +00:00
}
2017-06-14 01:06:45 +00:00
2017-07-13 00:07:31 +00:00
if ( $pmid ) {
// check comment permissions on the parent
2017-07-13 00:16:21 +00:00
$parent_item = 0 ;
$r = q ( " select * from item where parent_mid = '%s' and parent_mid = mid and uid = %d limit 1 " ,
2017-07-13 00:07:31 +00:00
dbesc ( $pmid ),
intval ( $importer [ 'channel_id' ])
);
if ( $r ) {
$parent_item = $r [ 0 ];
2017-07-13 00:16:21 +00:00
if ( intval ( $parent_item [ 'item_nocomment' ]) || $parent_item [ 'comment_policy' ] === 'none'
|| ( $parent_item [ 'comments_closed' ] > NULL_DATE && $parent_item [ 'comments_closed' ] < datetime_convert ())) {
logger ( 'comments disabled for post ' . $parent_item [ 'mid' ]);
continue ;
}
2017-07-13 00:07:31 +00:00
}
$allowed = false ;
if ( $parent_item ) {
if ( $parent_item [ 'owner_xchan' ] == $importer [ 'channel_hash' ])
$allowed = perm_is_allowed ( $importer [ 'channel_id' ], $contact [ 'xchan_hash' ], 'post_comments' );
else
$allowed = true ;
if ( ! $allowed ) {
logger ( 'Ignoring this comment author.' );
$status = 202 ;
continue ;
}
}
else {
if (( ! perm_is_allowed ( $importer [ 'channel_id' ], $contact [ 'xchan_hash' ], 'send_stream' )) && ( ! $importer [ 'system' ])) {
// @fixme check for and process ostatus autofriend
// otherwise
logger ( 'Ignoring this author.' );
continue ;
}
}
}
else {
2017-06-13 04:12:14 +00:00
// immediate parent wasn't found. Turn into a top-level post if permissions allow
2017-06-14 01:06:45 +00:00
// but save the thread_parent in case we need to refer to it later.
2017-06-13 04:12:14 +00:00
if ( ! post_is_importable ( $datarray , $contact ))
continue ;
$datarray [ 'parent_mid' ] = $datarray [ 'mid' ];
set_iconfig ( $datarray , 'system' , 'parent_mid' , $parent_mid , true );
}
2016-05-13 03:21:04 +00:00
$datarray [ 'aid' ] = $importer [ 'channel_account_id' ];
$datarray [ 'uid' ] = $importer [ 'channel_id' ];
2017-04-03 20:08:32 +00:00
logger ( 'data: ' . print_r ( $datarray , true ), LOGGER_DATA );
2016-05-13 03:21:04 +00:00
$xx = item_store ( $datarray );
$r = $xx [ 'item_id' ];
continue ;
}
else {
// Head post of a conversation. Have we seen it? If not, import it.
$author = array ();
$datarray = get_atom_elements ( $feed , $item , $author );
2017-06-15 03:20:18 +00:00
if ( ! $datarray [ 'mid' ])
continue ;
2017-03-04 19:56:59 +00:00
2017-07-15 22:49:10 +00:00
// A Mastodon privacy tag has been found. We cannot send private comments
// through the OStatus protocol, so block commenting.
if ( array_key_exists ( 'item_private' , $datarray ) && intval ( $datarray [ 'item_private' ])) {
$datarray [ 'public_policy' ] = 'specific' ;
$datarray [ 'comment_policy' ] = 'none' ;
}
2016-05-13 03:21:04 +00:00
if ( $contact [ 'xchan_network' ] === 'rss' ) {
$datarray [ 'public_policy' ] = 'specific' ;
$datarray [ 'comment_policy' ] = 'none' ;
}
2017-07-17 05:51:36 +00:00
// if we have everything but a photo, provide the default profile photo
if ( $author [ 'author_name' ] && $author [ 'author_link' ] && ( ! $author [ 'author_photo' ]))
$author [ 'author_photo' ] = z_root () . '/' . get_default_profile_photo ( 80 );
2016-05-13 03:21:04 +00:00
if ( is_array ( $contact )) {
if (( ! x ( $author , 'author_name' )) || ( $author [ 'author_is_feed' ]))
$author [ 'author_name' ] = $contact [ 'xchan_name' ];
if (( ! x ( $author , 'author_link' )) || ( $author [ 'author_is_feed' ]))
$author [ 'author_link' ] = $contact [ 'xchan_url' ];
if (( ! x ( $author , 'author_photo' )) || ( $author [ 'author_is_feed' ]))
$author [ 'author_photo' ] = $contact [ 'xchan_photo_m' ];
}
if (( ! x ( $author , 'author_name' )) || ( ! x ( $author , 'author_link' ))) {
2017-04-03 20:08:32 +00:00
logger ( 'No author information! ' . print_r ( $author , true ));
2016-05-13 03:21:04 +00:00
continue ;
}
$datarray [ 'author_xchan' ] = '' ;
if ( $author [ 'author_link' ] != $contact [ 'xchan_url' ]) {
2017-06-30 05:38:43 +00:00
$name = '' ;
if ( $author [ 'full_name' ]) {
$name = $author [ 'full_name' ];
if ( $author [ 'author_name' ])
$name .= ' (' . $author [ 'author_name' ] . ')' ;
}
else {
$name = $author [ 'author_name' ];
}
$x = import_author_unknown ( array ( 'name' => $name , 'url' => $author [ 'author_link' ], 'photo' => array ( 'src' => $author [ 'author_photo' ])));
2016-05-13 03:21:04 +00:00
if ( $x )
$datarray [ 'author_xchan' ] = $x ;
}
if ( ! $datarray [ 'author_xchan' ])
$datarray [ 'author_xchan' ] = $contact [ 'xchan_hash' ];
$datarray [ 'owner_xchan' ] = $contact [ 'xchan_hash' ];
2016-09-26 00:06:13 +00:00
if ( array_key_exists ( 'created' , $datarray ) && $datarray [ 'created' ] > NULL_DATE && $expire_days ) {
2016-05-13 03:21:04 +00:00
$t1 = $datarray [ 'created' ];
$t2 = datetime_convert ( 'UTC' , 'UTC' , 'now - ' . $expire_days . 'days' );
if ( $t1 < $t2 ) {
logger ( 'feed content older than expiration. Ignoring.' , LOGGER_DEBUG , LOG_INFO );
continue ;
}
}
$r = q ( " SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1 " ,
2017-06-15 03:20:18 +00:00
dbesc ( $datarray [ 'mid' ]),
2016-05-13 03:21:04 +00:00
intval ( $importer [ 'channel_id' ])
);
// Update content if 'updated' changes
if ( $r ) {
if (( x ( $datarray , 'edited' ) !== false )
&& ( datetime_convert ( 'UTC' , 'UTC' , $datarray [ 'edited' ]) !== $r [ 0 ][ 'edited' ])) {
// do not accept (ignore) an earlier edit than one we currently have.
if ( datetime_convert ( 'UTC' , 'UTC' , $datarray [ 'edited' ]) < $r [ 0 ][ 'edited' ])
continue ;
update_feed_item ( $importer [ 'channel_id' ], $datarray );
}
continue ;
}
2017-06-15 03:20:18 +00:00
$datarray [ 'parent_mid' ] = $datarray [ 'mid' ];
2016-05-13 03:21:04 +00:00
$datarray [ 'uid' ] = $importer [ 'channel_id' ];
$datarray [ 'aid' ] = $importer [ 'channel_account_id' ];
2017-04-03 20:08:32 +00:00
if ( ! link_compare ( $author [ 'owner_link' ], $contact [ 'xchan_url' ])) {
logger ( 'Correcting item owner.' , LOGGER_DEBUG );
2016-05-13 03:21:04 +00:00
$author [ 'owner_name' ] = $contact [ 'name' ];
$author [ 'owner_link' ] = $contact [ 'url' ];
$author [ 'owner_avatar' ] = $contact [ 'thumb' ];
}
2017-04-03 20:08:32 +00:00
if ( ! post_is_importable ( $datarray , $contact ))
2016-05-13 03:21:04 +00:00
continue ;
2017-04-03 20:08:32 +00:00
logger ( 'author: ' . print_r ( $author , true ), LOGGER_DEBUG );
logger ( 'data: ' . print_r ( $datarray , true ), LOGGER_DATA );
2016-05-13 03:21:04 +00:00
$xx = item_store ( $datarray );
$r = $xx [ 'item_id' ];
2017-04-03 20:08:32 +00:00
2016-05-13 03:21:04 +00:00
continue ;
}
}
}
}
2017-06-28 02:20:13 +00:00
function feed_conversation_fetch ( $importer , $contact , $parent_link ) {
2017-06-28 02:57:03 +00:00
logger ( 'parent_link: ' . $parent_link , LOGGER_DEBUG , LOG_INFO );
2017-06-28 02:20:13 +00:00
$link = '' ;
// GNU-Social flavoured feeds
if ( strpos ( $parent_link , '/notice/' )) {
2017-06-28 22:58:14 +00:00
$link = str_replace ( '/notice/' , '/api/statuses/show/' , $parent_link ) . '.atom' ;
2017-06-28 02:20:13 +00:00
}
// Mastodon flavoured feeds
if ( strpos ( $parent_link , '/users/' ) && strpos ( $parent_link , '/updates/' )) {
2017-06-28 23:02:44 +00:00
$link = $parent_link . '.atom' ;
2017-06-28 02:20:13 +00:00
}
if ( ! $link )
return false ;
2017-06-29 02:20:11 +00:00
logger ( 'fetching: ' . $link , LOGGER_DEBUG , LOG_INFO );
2017-06-28 02:20:13 +00:00
$fetch = z_fetch_url ( $link );
if ( ! $fetch [ 'success' ])
return false ;
2017-06-29 02:34:49 +00:00
$data = $fetch [ 'body' ];
2017-06-29 02:20:11 +00:00
2017-06-29 02:34:49 +00:00
// We will probably receive an atom 'entry' and not an atom 'feed'. Unfortunately
// our parser is a bit strict about compliance so we'll insert just enough of a feed
// tag to trick it into believing it's a compliant feed.
if ( ! strstr ( $data , '<feed' )) {
$data = str_replace ( '<entry ' , '<feed xmlns="http://www.w3.org/2005/Atom"><entry ' , $data );
$data .= '</feed>' ;
}
consume_feed ( $data , $importer , $contact , 1 );
consume_feed ( $data , $importer , $contact , 2 );
2017-06-30 04:09:08 +00:00
return true ;
2017-06-28 02:20:13 +00:00
}
2017-04-03 20:08:32 +00:00
/**
* @ brief Normalise an id .
*
* Strip " X-ZOT: " from $id .
*
* @ param string $id
* @ return string
*/
2017-01-10 22:25:11 +00:00
function normalise_id ( $id ) {
2017-04-03 20:08:32 +00:00
return str_replace ( 'X-ZOT:' , '' , $id );
2017-01-10 22:25:11 +00:00
}
2016-05-13 03:21:04 +00:00
/**
2017-04-03 20:08:32 +00:00
* @ brief Process atom feed and return the first post and structure .
2016-05-13 03:21:04 +00:00
*
2017-04-03 20:08:32 +00:00
* @ param string $xml
2016-05-13 03:21:04 +00:00
* The ( atom ) feed to consume - RSS isn ' t as fully supported but may work for simple feeds .
* @ param $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 .
*/
function process_salmon_feed ( $xml , $importer ) {
$ret = array ();
if ( ! strlen ( $xml )) {
logger ( 'process_feed: empty input' );
return ;
}
$feed = new SimplePie ();
$feed -> set_raw_data ( $xml );
2017-04-03 20:08:32 +00:00
// We can preserve iframes because we will strip them in the purifier after
// checking for supported video sources.
$strip_htmltags = $feed -> strip_htmltags ;
array_splice ( $strip_htmltags , array_search ( 'iframe' , $strip_htmltags ), 1 );
$feed -> strip_htmltags ( $strip_htmltags );
2016-05-13 03:21:04 +00:00
$feed -> init ();
if ( $feed -> error ())
logger ( 'Error parsing XML: ' . $feed -> error ());
$permalink = $feed -> get_permalink ();
if ( $feed -> get_item_quantity ()) {
// this should be exactly one
logger ( 'feed item count = ' . $feed -> get_item_quantity (), LOGGER_DEBUG );
$items = $feed -> get_items ();
foreach ( $items as $item ) {
2017-01-10 22:25:11 +00:00
$item_id = normalise_id ( $item -> get_id ());
2016-05-13 03:21:04 +00:00
logger ( 'processing ' . $item_id , LOGGER_DEBUG );
2017-04-03 20:08:32 +00:00
$rawthread = $item -> get_item_tags ( NAMESPACE_THREAD , 'in-reply-to' );
2016-05-13 03:21:04 +00:00
if ( isset ( $rawthread [ 0 ][ 'attribs' ][ '' ][ 'ref' ])) {
$is_reply = true ;
2017-01-10 22:25:11 +00:00
$parent_mid = normalise_id ( $rawthread [ 0 ][ 'attribs' ][ '' ][ 'ref' ]);
2016-05-13 03:21:04 +00:00
}
if ( $is_reply )
$ret [ 'parent_mid' ] = $parent_mid ;
$ret [ 'author' ] = array ();
2017-04-03 20:08:32 +00:00
$datarray = get_atom_elements ( $feed , $item , $ret [ 'author' ]);
2016-05-13 03:21:04 +00:00
// reset policies which are restricted by default for RSS connections
2017-04-03 20:08:32 +00:00
// This item is likely coming from GNU-social via salmon and allows public interaction
2016-05-13 03:21:04 +00:00
$datarray [ 'public_policy' ] = '' ;
$datarray [ 'comment_policy' ] = '' ;
2017-04-03 20:08:32 +00:00
$ret [ 'item' ] = $datarray ;
2016-05-13 03:21:04 +00:00
}
}
return $ret ;
}
2017-04-03 20:08:32 +00:00
/**
* @ brief Given an xml ( atom ) feed , find author and hub links .
*
* @ param string $xml
* @ return array
*/
2016-05-13 03:21:04 +00:00
function feed_meta ( $xml ) {
$ret = array ();
2017-04-03 20:08:32 +00:00
if ( ! strlen ( $xml )) {
logger ( 'empty input' );
return $ret ;
}
2016-05-13 03:21:04 +00:00
2017-04-03 20:08:32 +00:00
$feed = new SimplePie ();
$feed -> set_raw_data ( $xml );
$feed -> init ();
2016-05-13 03:21:04 +00:00
2017-04-03 20:08:32 +00:00
if ( $feed -> error ()) {
logger ( 'Error parsing XML: ' . $feed -> error ());
2016-05-13 03:21:04 +00:00
return $ret ;
}
2017-04-03 20:08:32 +00:00
$ret [ 'hubs' ] = $feed -> get_links ( 'hub' );
//logger('hubs: ' . print_r($hubs,true), LOGGER_DATA);
2016-05-13 03:21:04 +00:00
$author = array ();
2017-04-03 20:08:32 +00:00
$found_author = $feed -> get_author ();
if ( $found_author ) {
$author [ 'author_name' ] = unxmlify ( $found_author -> get_name ());
$author [ 'author_link' ] = unxmlify ( $found_author -> get_link ());
2016-05-13 03:21:04 +00:00
2017-04-03 20:08:32 +00:00
$rawauthor = $feed -> get_feed_tags ( SIMPLEPIE_NAMESPACE_ATOM_10 , 'author' );
logger ( 'rawauthor: ' . print_r ( $rawauthor , true ));
2016-05-13 03:21:04 +00:00
2017-04-03 20:08:32 +00:00
if ( $rawauthor ) {
2016-05-13 03:21:04 +00:00
if ( $rawauthor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'link' ]) {
2017-04-03 20:08:32 +00:00
$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' ]);
2016-05-13 03:21:04 +00:00
break ;
}
2017-04-03 20:08:32 +00:00
}
}
2016-05-13 03:21:04 +00:00
}
if ( $rawauthor [ 0 ][ 'child' ][ NAMESPACE_POCO ][ 'displayName' ][ 0 ][ 'data' ])
$author [ 'full_name' ] = unxmlify ( $rawauthor [ 0 ][ 'child' ][ NAMESPACE_POCO ][ 'displayName' ][ 0 ][ 'data' ]);
if ( $rawauthor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'uri' ][ 0 ][ 'data' ])
$author [ 'author_uri' ] = unxmlify ( $rawauthor [ 0 ][ 'child' ][ SIMPLEPIE_NAMESPACE_ATOM_10 ][ 'uri' ][ 0 ][ 'data' ]);
}
2017-04-03 20:08:32 +00:00
}
2016-05-13 03:21:04 +00:00
2017-06-08 04:49:50 +00:00
if ( ! $author [ 'author_photo' ])
$author [ 'author_photo' ] = $feed -> get_image_url ();
2017-04-03 20:08:32 +00:00
if ( substr ( $author [ 'author_link' ], - 1 , 1 ) == '/' )
$author [ 'author_link' ] = substr ( $author [ 'author_link' ], 0 , - 1 );
2016-05-13 03:21:04 +00:00
2017-04-03 20:08:32 +00:00
$ret [ 'author' ] = $author ;
2016-05-13 03:21:04 +00:00
return $ret ;
}
2017-04-03 20:08:32 +00:00
/**
* @ brief Not yet implemented function to update feed item .
*
* @ param int $uid
* @ param array $datarray
*/
function update_feed_item ( $uid , $datarray ) {
logger ( 'Not implemented! ' . $uid . ' ' . print_r ( $datarray , true ), LOGGER_DATA );
2016-05-13 03:21:04 +00:00
}
2017-04-03 20:08:32 +00:00
/**
* @ brief Fetch the content of a feed and further consume it .
*
* It will first process parent items and in a second run child items .
* @ see consume_feed ()
*
* @ param int $uid
* @ param int $abook_id
* @ param string $url URL of the feed
*/
function handle_feed ( $uid , $abook_id , $url ) {
2016-05-13 03:21:04 +00:00
$channel = channelx_by_n ( $uid );
if ( ! $channel )
return ;
$x = q ( " select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d limit 1 " ,
dbesc ( $abook_id ),
intval ( $uid )
);
$recurse = 0 ;
2017-04-03 20:08:32 +00:00
$z = z_fetch_url ( $url , false , $recurse , array ( 'novalidate' => true ));
2016-05-13 03:21:04 +00:00
2017-04-03 20:08:32 +00:00
//logger('data:' . print_r($z, true), LOGGER_DATA);
2016-05-13 03:21:04 +00:00
if ( $z [ 'success' ]) {
2017-04-03 20:08:32 +00:00
consume_feed ( $z [ 'body' ], $channel , $x [ 0 ], 1 );
consume_feed ( $z [ 'body' ], $channel , $x [ 0 ], 2 );
2016-05-13 03:21:04 +00:00
}
}
2017-04-03 20:08:32 +00:00
/**
* @ brief Return a XML tag with author information .
*
2017-05-04 22:23:57 +00:00
* @ hooks \b atom_author Possibility to add further tags to returned XML string
* * \e string The created XML tag as a string without closing tag
2017-04-03 20:08:32 +00:00
* @ param string $tag The XML tag to create
2017-05-04 22:23:57 +00:00
* @ param string $nick preferred username
* @ param string $name displayed name of the author
2017-04-03 20:08:32 +00:00
* @ param string $uri
* @ param int $h image height
* @ param int $w image width
* @ param string $type profile photo mime type
* @ param string $photo Fully qualified URL to a profile / avator photo
* @ return string
*/
2017-04-27 23:50:37 +00:00
function atom_author ( $tag , $nick , $name , $uri , $h , $w , $type , $photo ) {
2016-05-13 03:21:04 +00:00
$o = '' ;
if ( ! $tag )
return $o ;
2017-04-27 23:50:37 +00:00
$nick = xmlify ( $nick );
2016-05-13 03:21:04 +00:00
$name = xmlify ( $name );
$uri = xmlify ( $uri );
$h = intval ( $h );
$w = intval ( $w );
$photo = xmlify ( $photo );
$o .= " < $tag > \r \n " ;
2017-04-26 03:48:38 +00:00
$o .= " <id> $uri </id> \r \n " ;
2017-04-27 23:50:37 +00:00
$o .= " <name> $nick </name> \r \n " ;
2017-04-26 03:48:38 +00:00
$o .= " <uri> $uri </uri> \r \n " ;
$o .= ' <link rel="photo" type="' . $type . '" media:width="' . $w . '" media:height="' . $h . '" href="' . $photo . '" />' . " \r \n " ;
$o .= ' <link rel="avatar" type="' . $type . '" media:width="' . $w . '" media:height="' . $h . '" href="' . $photo . '" />' . " \r \n " ;
2017-04-27 23:50:37 +00:00
$o .= ' <poco:preferredUsername>' . $nick . '</poco:preferredUsername>' . " \r \n " ;
$o .= ' <poco:displayName>' . $name . '</poco:displayName>' . " \r \n " ;
2016-05-13 03:21:04 +00:00
call_hooks ( 'atom_author' , $o );
$o .= " </ $tag > \r \n " ;
return $o ;
}
2017-05-12 00:39:26 +00:00
function atom_render_author ( $tag , $xchan ) {
$nick = xmlify ( substr ( $xchan [ 'xchan_addr' ], 0 , strpos ( $xchan [ 'xchan_addr' ], '@' )));
$id = xmlify ( $xchan [ 'xchan_url' ]);
$name = xmlify ( $xchan [ 'xchan_name' ]);
$photo = xmlify ( $xchan [ 'xchan_photo_l' ]);
$type = xmlify ( $xchan [ 'xchan_photo_mimetype' ]);
$w = $h = 300 ;
$o .= " < $tag > \r \n " ;
$o .= " <as:object-type>http://activitystrea.ms/schema/1.0/person</as:object-type> \r \n " ;
$o .= " <id> $id </id> \r \n " ;
$o .= " <name> $nick </name> \r \n " ;
$o .= " <uri> $id </uri> \r \n " ;
$o .= ' <link rel="alternate" type="text/html" href="' . $id . '" />' . " \r \n " ;
$o .= ' <link rel="photo" type="' . $type . '" media:width="' . $w . '" media:height="' . $h . '" href="' . $photo . '" />' . " \r \n " ;
$o .= ' <link rel="avatar" type="' . $type . '" media:width="' . $w . '" media:height="' . $h . '" href="' . $photo . '" />' . " \r \n " ;
$o .= ' <poco:preferredUsername>' . $nick . '</poco:preferredUsername>' . " \r \n " ;
$o .= ' <poco:displayName>' . $name . '</poco:displayName>' . " \r \n " ;
call_hooks ( 'atom_render_author' , $o );
$o .= " </ $tag > \r \n " ;
return $o ;
}
2017-06-05 02:09:05 +00:00
function compat_photos_list ( $s ) {
$ret = [];
$found = preg_match_all ( '/\[[zi]mg(.*?)\](.*?)\[/ism' , $s , $matches , PREG_SET_ORDER );
if ( $found ) {
foreach ( $matches as $match ) {
$ret [] = [
'href' => $match [ 2 ],
'length' => 0 ,
'type' => guess_image_type ( $match [ 2 ])
];
}
}
return $ret ;
}
2017-04-03 20:08:32 +00:00
/**
* @ brief Create an item for the Atom feed .
*
* @ see get_feed_for ()
*
* @ param array $item
* @ param string $type
* @ param array $author
* @ param array $owner
* @ param string $comment default false
* @ param number $cid default 0
* @ return void | string
*/
2017-06-05 02:09:05 +00:00
function atom_entry ( $item , $type , $author , $owner , $comment = false , $cid = 0 , $compat = false ) {
2016-05-13 03:21:04 +00:00
if ( ! $item [ 'parent' ])
return ;
if ( $item [ 'deleted' ])
return '<at:deleted-entry ref="' . xmlify ( $item [ 'mid' ]) . '" when="' . xmlify ( datetime_convert ( 'UTC' , 'UTC' , $item [ 'edited' ] . '+00:00' , ATOM_TIME )) . '" />' . " \r \n " ;
create_export_photo_body ( $item );
if ( $item [ 'allow_cid' ] || $item [ 'allow_gid' ] || $item [ 'deny_cid' ] || $item [ 'deny_gid' ])
$body = fix_private_photos ( $item [ 'body' ], $owner [ 'uid' ], $item , $cid );
else
$body = $item [ 'body' ];
2017-06-05 02:09:05 +00:00
if ( $compat ) {
$compat_photos = compat_photos_list ( $body );
}
else {
$compat_photos = null ;
}
2016-05-13 03:21:04 +00:00
$o = " \r \n \r \n <entry> \r \n " ;
2017-04-27 23:50:37 +00:00
if ( is_array ( $author )) {
2017-05-12 00:39:26 +00:00
$o .= atom_render_author ( 'author' , $author );
2017-04-27 23:50:37 +00:00
}
else {
2017-05-12 00:39:26 +00:00
$o .= atom_render_author ( 'author' , $item [ 'author' ]);
2017-04-27 23:50:37 +00:00
}
2016-05-13 03:21:04 +00:00
2017-05-12 00:39:26 +00:00
$o .= atom_render_author ( 'zot:owner' , $item [ 'owner' ]);
2016-05-13 03:21:04 +00:00
if (( $item [ 'parent' ] != $item [ 'id' ]) || ( $item [ 'parent_mid' ] !== $item [ 'mid' ]) || (( $item [ 'thr_parent' ] !== '' ) && ( $item [ 'thr_parent' ] !== $item [ 'mid' ]))) {
$parent_item = (( $item [ 'thr_parent' ]) ? $item [ 'thr_parent' ] : $item [ 'parent_mid' ]);
2017-06-15 02:59:25 +00:00
// ensure it's a legal uri and not just a message-id
if ( ! strpos ( $parent_item , ':' ))
$parent_item = 'X-ZOT:' . $parent_item ;
2017-06-14 22:19:50 +00:00
$o .= '<thr:in-reply-to ref="' . xmlify ( $parent_item ) . '" type="text/html" href="' . xmlify ( $item [ 'plink' ]) . '" />' . " \r \n " ;
2016-05-13 03:21:04 +00:00
}
if ( activity_match ( $item [ 'obj_type' ], ACTIVITY_OBJ_EVENT ) && activity_match ( $item [ 'verb' ], ACTIVITY_POST )) {
2016-06-02 04:48:54 +00:00
$obj = (( is_array ( $item [ 'obj' ])) ? $item [ 'obj' ] : json_decode ( $item [ 'obj' ], true ));
2017-04-03 20:08:32 +00:00
2016-05-13 03:21:04 +00:00
$o .= '<title>' . xmlify ( $item [ 'title' ]) . '</title>' . " \r \n " ;
$o .= '<summary xmlns="urn:ietf:params:xml:ns:xcal">' . xmlify ( bbcode ( $obj [ 'title' ])) . '</summary>' . " \r \n " ;
2016-06-02 04:48:54 +00:00
$o .= '<dtstart xmlns="urn:ietf:params:xml:ns:xcal">' . datetime_convert ( 'UTC' , 'UTC' , $obj [ 'dtstart' ], 'Ymd\\THis' . (( $obj [ 'adjust' ]) ? '\\Z' : '' )) . '</dtstart>' . " \r \n " ;
$o .= '<dtend xmlns="urn:ietf:params:xml:ns:xcal">' . datetime_convert ( 'UTC' , 'UTC' , $obj [ 'dtend' ], 'Ymd\\THis' . (( $obj [ 'adjust' ]) ? '\\Z' : '' )) . '</dtend>' . " \r \n " ;
2016-05-13 03:21:04 +00:00
$o .= '<location xmlns="urn:ietf:params:xml:ns:xcal">' . xmlify ( bbcode ( $obj [ 'location' ])) . '</location>' . " \r \n " ;
$o .= '<content type="' . $type . '" >' . xmlify ( bbcode ( $obj [ 'description' ])) . '</content>' . " \r \n " ;
}
else {
$o .= '<title>' . xmlify ( $item [ 'title' ]) . '</title>' . " \r \n " ;
$o .= '<content type="' . $type . '" >' . xmlify ( prepare_text ( $body , $item [ 'mimetype' ])) . '</content>' . " \r \n " ;
}
2017-01-10 22:25:11 +00:00
$o .= '<id>' . 'X-ZOT:' . xmlify ( $item [ 'mid' ]) . '</id>' . " \r \n " ;
2016-05-13 03:21:04 +00:00
$o .= '<published>' . xmlify ( datetime_convert ( 'UTC' , 'UTC' , $item [ 'created' ] . '+00:00' , ATOM_TIME )) . '</published>' . " \r \n " ;
$o .= '<updated>' . xmlify ( datetime_convert ( 'UTC' , 'UTC' , $item [ 'edited' ] . '+00:00' , ATOM_TIME )) . '</updated>' . " \r \n " ;
$o .= '<link rel="alternate" type="text/html" href="' . xmlify ( $item [ 'plink' ]) . '" />' . " \r \n " ;
if ( $item [ 'location' ]) {
$o .= '<zot:location>' . xmlify ( $item [ 'location' ]) . '</zot:location>' . " \r \n " ;
$o .= '<poco:address><poco:formatted>' . xmlify ( $item [ 'location' ]) . '</poco:formatted></poco:address>' . " \r \n " ;
}
if ( $item [ 'coord' ])
$o .= '<georss:point>' . xmlify ( $item [ 'coord' ]) . '</georss:point>' . " \r \n " ;
if (( $item [ 'item_private' ]) || strlen ( $item [ 'allow_cid' ]) || strlen ( $item [ 'allow_gid' ]) || strlen ( $item [ 'deny_cid' ]) || strlen ( $item [ 'deny_gid' ]))
$o .= '<zot:private>' . (( $item [ 'item_private' ]) ? $item [ 'item_private' ] : 1 ) . '</zot:private>' . " \r \n " ;
if ( $item [ 'app' ])
$o .= '<statusnet:notice_info local_id="' . $item [ 'id' ] . '" source="' . xmlify ( $item [ 'app' ]) . '" ></statusnet:notice_info>' . " \r \n " ;
$verb = construct_verb ( $item );
$o .= '<as:verb>' . xmlify ( $verb ) . '</as:verb>' . " \r \n " ;
$actobj = construct_activity_object ( $item );
if ( strlen ( $actobj ))
$o .= $actobj ;
2017-04-03 20:08:32 +00:00
2016-05-13 03:21:04 +00:00
$actarg = construct_activity_target ( $item );
if ( strlen ( $actarg ))
$o .= $actarg ;
2017-01-07 21:29:32 +00:00
if ( $item [ 'attach' ]) {
2017-04-03 20:08:32 +00:00
$enclosures = json_decode ( $item [ 'attach' ], true );
2017-01-07 21:29:32 +00:00
if ( $enclosures ) {
foreach ( $enclosures as $enc ) {
$o .= '<link rel="enclosure" '
. (( $enc [ 'href' ]) ? 'href="' . $enc [ 'href' ] . '" ' : '' )
. (( $enc [ 'length' ]) ? 'length="' . $enc [ 'length' ] . '" ' : '' )
. (( $enc [ 'type' ]) ? 'type="' . $enc [ 'type' ] . '" ' : '' )
2017-06-05 02:09:05 +00:00
. ' />' . " \r \n " ;
2017-01-07 21:29:32 +00:00
}
}
}
2017-06-05 02:09:05 +00:00
if ( $compat_photos ) {
foreach ( $compat_photos as $enc ) {
$o .= '<link rel="enclosure" '
. (( $enc [ 'href' ]) ? 'href="' . $enc [ 'href' ] . '" ' : '' )
2017-06-05 03:07:08 +00:00
. (( array_key_exists ( 'length' , $enc )) ? 'length="' . $enc [ 'length' ] . '" ' : '' )
2017-06-05 02:09:05 +00:00
. (( $enc [ 'type' ]) ? 'type="' . $enc [ 'type' ] . '" ' : '' )
. ' />' . " \r \n " ;
}
}
2017-01-07 21:29:32 +00:00
if ( $item [ 'term' ]) {
foreach ( $item [ 'term' ] as $term ) {
$scheme = '' ;
2017-04-03 20:08:32 +00:00
$label = '' ;
2017-01-07 21:29:32 +00:00
switch ( $term [ 'ttype' ]) {
case TERM_UNKNOWN :
$scheme = NAMESPACE_ZOT . '/term/unknown' ;
$label = $term [ 'term' ];
break ;
case TERM_HASHTAG :
case TERM_COMMUNITYTAG :
$scheme = NAMESPACE_ZOT . '/term/hashtag' ;
$label = '#' . $term [ 'term' ];
break ;
case TERM_MENTION :
$scheme = NAMESPACE_ZOT . '/term/mention' ;
$label = '@' . $term [ 'term' ];
break ;
case TERM_CATEGORY :
$scheme = NAMESPACE_ZOT . '/term/category' ;
$label = $term [ 'term' ];
break ;
default :
break ;
}
if ( ! $scheme )
continue ;
2016-05-13 03:21:04 +00:00
2017-01-07 21:29:32 +00:00
$o .= '<category scheme="' . $scheme . '" term="' . $term [ 'term' ] . '" label="' . $label . '" />' . " \r \n " ;
}
}
2016-05-13 03:21:04 +00:00
$o .= '</entry>' . " \r \n " ;
2017-04-03 20:08:32 +00:00
// build array to pass to hook
$x = [
'item' => $item ,
'type' => $type ,
'author' => $author ,
'owner' => $owner ,
'comment' => $comment ,
'abook_id' => $cid ,
'entry' => $o
2017-01-07 12:04:11 +00:00
];
call_hooks ( 'atom_entry' , $x );
return $x [ 'entry' ];
2016-05-13 03:21:04 +00:00
}
2017-04-03 20:08:32 +00:00
/**
* @ brief
*
* @ param array $items
* @ return array
*/
2016-05-13 03:21:04 +00:00
function gen_asld ( $items ) {
$ret = array ();
if ( ! $items )
return $ret ;
2017-04-03 20:08:32 +00:00
2016-05-13 03:21:04 +00:00
foreach ( $items as $item ) {
$ret [] = i2asld ( $item );
}
2017-04-03 20:08:32 +00:00
2016-05-13 03:21:04 +00:00
return $ret ;
}
2017-04-03 20:08:32 +00:00
/**
* @ brief
*
* @ param array $i
* @ return array
*/
2016-05-13 03:21:04 +00:00
function i2asld ( $i ) {
if ( ! $i )
return array ();
$ret = array ();
$ret [ '@context' ] = array ( 'http://www.w3.org/ns/activitystreams' , 'zot' => 'http://purl.org/zot/protocol' );
if ( $i [ 'verb' ]) {
if ( strpos ( dirname ( $i [ 'verb' ], 'activitystrea.ms/schema/1.0' ))) {
$ret [ '@type' ] = ucfirst ( basename ( $i [ 'verb' ]));
}
elseif ( strpos ( dirname ( $i [ 'verb' ], 'purl.org/zot' ))) {
$ret [ '@type' ] = 'zot:' . ucfirst ( basename ( $i [ 'verb' ]));
}
}
$ret [ '@id' ] = $i [ 'plink' ];
$ret [ 'published' ] = datetime_convert ( 'UTC' , 'UTC' , $i [ 'created' ], ATOM_TIME );
// we need to pass the parent into this
// if($i['id'] != $i['parent'] && $i['obj_type'] === ACTIVITY_OBJ_NOTE) {
// $ret['inReplyTo'] = asencode_note
// }
if ( $i [ 'obj_type' ] === ACTIVITY_OBJ_NOTE )
$ret [ 'object' ] = asencode_note ( $i );
$ret [ 'actor' ] = asencode_person ( $i [ 'author' ]);
return $ret ;
}
function asencode_note ( $i ) {
$ret = array ();
$ret [ '@type' ] = 'Note' ;
$ret [ '@id' ] = $i [ 'plink' ];
if ( $i [ 'title' ])
$ret [ 'title' ] = bbcode ( $i [ 'title' ]);
2017-04-03 20:08:32 +00:00
2016-05-13 03:21:04 +00:00
$ret [ 'content' ] = bbcode ( $i [ 'body' ]);
$ret [ 'zot:owner' ] = asencode_person ( $i [ 'owner' ]);
$ret [ 'published' ] = datetime_convert ( 'UTC' , 'UTC' , $i [ 'created' ], ATOM_TIME );
if ( $i [ 'created' ] !== $i [ 'edited' ])
$ret [ 'updated' ] = datetime_convert ( 'UTC' , 'UTC' , $i [ 'edited' ], ATOM_TIME );
return $ret ;
}
function asencode_person ( $p ) {
$ret = array ();
$ret [ '@type' ] = 'Person' ;
$ret [ '@id' ] = 'acct:' . $p [ 'xchan_addr' ];
$ret [ 'displayName' ] = $p [ 'xchan_name' ];
$ret [ 'icon' ] = array (
'@type' => 'Link' ,
'mediaType' => $p [ 'xchan_photo_mimetype' ],
'href' => $p [ 'xchan_photo_m' ]
);
$ret [ 'url' ] = array (
'@type' => 'Link' ,
'mediaType' => 'text/html' ,
'href' => $p [ 'xchan_url' ]
);
return $ret ;
}
2017-06-17 02:30:02 +00:00