Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3565 lines
116 KiB

11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
9 years ago
11 years ago
11 years ago
10 years ago
11 years ago
9 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. <?php
  2. require_once('include/bbcode.php');
  3. require_once('include/oembed.php');
  4. require_once('include/salmon.php');
  5. require_once('include/crypto.php');
  6. function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) {
  7. $sitefeed = ((strlen($owner_nick)) ? false : true); // not yet implemented, need to rewrite huge chunks of following logic
  8. $public_feed = (($dfrn_id) ? false : true);
  9. $starred = false; // not yet implemented, possible security issues
  10. $converse = false;
  11. if($public_feed && $a->argc > 2) {
  12. for($x = 2; $x < $a->argc; $x++) {
  13. if($a->argv[$x] == 'converse')
  14. $converse = true;
  15. if($a->argv[$x] == 'starred')
  16. $starred = true;
  17. if($a->argv[$x] === 'category' && $a->argc > ($x + 1) && strlen($a->argv[$x+1]))
  18. $category = $a->argv[$x+1];
  19. }
  20. }
  21. // default permissions - anonymous user
  22. $sql_extra = " AND `allow_cid` = '' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = '' ";
  23. $r = q("SELECT `contact`.*, `user`.`uid` AS `user_uid`, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags`
  24. FROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid`
  25. WHERE `contact`.`self` = 1 AND `user`.`nickname` = '%s' LIMIT 1",
  26. dbesc($owner_nick)
  27. );
  28. if(! count($r))
  29. killme();
  30. $owner = $r[0];
  31. $owner_id = $owner['user_uid'];
  32. $owner_nick = $owner['nickname'];
  33. $birthday = feed_birthday($owner_id,$owner['timezone']);
  34. if(! $public_feed) {
  35. $sql_extra = '';
  36. switch($direction) {
  37. case (-1):
  38. $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($dfrn_id));
  39. $my_id = $dfrn_id;
  40. break;
  41. case 0:
  42. $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
  43. $my_id = '1:' . $dfrn_id;
  44. break;
  45. case 1:
  46. $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
  47. $my_id = '0:' . $dfrn_id;
  48. break;
  49. default:
  50. return false;
  51. break; // NOTREACHED
  52. }
  53. $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `contact`.`uid` = %d $sql_extra LIMIT 1",
  54. intval($owner_id)
  55. );
  56. if(! count($r))
  57. killme();
  58. $contact = $r[0];
  59. $groups = init_groups_visitor($contact['id']);
  60. if(count($groups)) {
  61. for($x = 0; $x < count($groups); $x ++)
  62. $groups[$x] = '<' . intval($groups[$x]) . '>' ;
  63. $gs = implode('|', $groups);
  64. }
  65. else
  66. $gs = '<<>>' ; // Impossible to match
  67. $sql_extra = sprintf("
  68. AND ( `allow_cid` = '' OR `allow_cid` REGEXP '<%d>' )
  69. AND ( `deny_cid` = '' OR NOT `deny_cid` REGEXP '<%d>' )
  70. AND ( `allow_gid` = '' OR `allow_gid` REGEXP '%s' )
  71. AND ( `deny_gid` = '' OR NOT `deny_gid` REGEXP '%s')
  72. ",
  73. intval($contact['id']),
  74. intval($contact['id']),
  75. dbesc($gs),
  76. dbesc($gs)
  77. );
  78. }
  79. if($public_feed)
  80. $sort = 'DESC';
  81. else
  82. $sort = 'ASC';
  83. if(! strlen($last_update))
  84. $last_update = 'now -30 days';
  85. if(isset($category)) {
  86. $sql_extra .= file_tag_file_query('item',$category,'category');
  87. }
  88. if($public_feed) {
  89. if(! $converse)
  90. $sql_extra .= " AND `contact`.`self` = 1 ";
  91. }
  92. $check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s');
  93. $r = q("SELECT `item`.*, `item`.`id` AS `item_id`,
  94. `contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`,
  95. `contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`,
  96. `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
  97. `contact`.`id` AS `contact-id`, `contact`.`uid` AS `contact-uid`,
  98. `sign`.`signed_text`, `sign`.`signature`, `sign`.`signer`
  99. FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
  100. LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id`
  101. WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`parent` != 0
  102. AND `item`.`wall` = 1 AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
  103. AND ( `item`.`edited` > '%s' OR `item`.`changed` > '%s' )
  104. $sql_extra
  105. ORDER BY `parent` %s, `created` ASC LIMIT 0, 300",
  106. intval($owner_id),
  107. dbesc($check_date),
  108. dbesc($check_date),
  109. dbesc($sort)
  110. );
  111. // Will check further below if this actually returned results.
  112. // We will provide an empty feed if that is the case.
  113. $items = $r;
  114. $feed_template = get_markup_template(($dfrn_id) ? 'atom_feed_dfrn.tpl' : 'atom_feed.tpl');
  115. $atom = '';
  116. $hubxml = feed_hublinks();
  117. $salmon = feed_salmonlinks($owner_nick);
  118. $atom .= replace_macros($feed_template, array(
  119. '$version' => xmlify(FRIENDICA_VERSION),
  120. '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner_nick),
  121. '$feed_title' => xmlify($owner['name']),
  122. '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now' , ATOM_TIME)) ,
  123. '$hub' => $hubxml,
  124. '$salmon' => $salmon,
  125. '$name' => xmlify($owner['name']),
  126. '$profile_page' => xmlify($owner['url']),
  127. '$photo' => xmlify($owner['photo']),
  128. '$thumb' => xmlify($owner['thumb']),
  129. '$picdate' => xmlify(datetime_convert('UTC','UTC',$owner['avatar-date'] . '+00:00' , ATOM_TIME)) ,
  130. '$uridate' => xmlify(datetime_convert('UTC','UTC',$owner['uri-date'] . '+00:00' , ATOM_TIME)) ,
  131. '$namdate' => xmlify(datetime_convert('UTC','UTC',$owner['name-date'] . '+00:00' , ATOM_TIME)) ,
  132. '$birthday' => ((strlen($birthday)) ? '<dfrn:birthday>' . xmlify($birthday) . '</dfrn:birthday>' : ''),
  133. '$community' => (($owner['page-flags'] == PAGE_COMMUNITY) ? '<dfrn:community>1</dfrn:community>' : '')
  134. ));
  135. call_hooks('atom_feed', $atom);
  136. if(! count($items)) {
  137. call_hooks('atom_feed_end', $atom);
  138. $atom .= '</feed>' . "\r\n";
  139. return $atom;
  140. }
  141. foreach($items as $item) {
  142. // prevent private email from leaking.
  143. if($item['network'] === NETWORK_MAIL)
  144. continue;
  145. // public feeds get html, our own nodes use bbcode
  146. if($public_feed) {
  147. $type = 'html';
  148. // catch any email that's in a public conversation and make sure it doesn't leak
  149. if($item['private'])
  150. continue;
  151. }
  152. else {
  153. $type = 'text';
  154. }
  155. $atom .= atom_entry($item,$type,null,$owner,true);
  156. }
  157. call_hooks('atom_feed_end', $atom);
  158. $atom .= '</feed>' . "\r\n";
  159. return $atom;
  160. }
  161. function construct_verb($item) {
  162. if($item['verb'])
  163. return $item['verb'];
  164. return ACTIVITY_POST;
  165. }
  166. function construct_activity_object($item) {
  167. if($item['object']) {
  168. $o = '<as:object>' . "\r\n";
  169. $r = parse_xml_string($item['object'],false);
  170. if(! $r)
  171. return '';
  172. if($r->type)
  173. $o .= '<as:object-type>' . xmlify($r->type) . '</as:object-type>' . "\r\n";
  174. if($r->id)
  175. $o .= '<id>' . xmlify($r->id) . '</id>' . "\r\n";
  176. if($r->title)
  177. $o .= '<title>' . xmlify($r->title) . '</title>' . "\r\n";
  178. if($r->link) {
  179. if(substr($r->link,0,1) === '<') {
  180. // patch up some facebook "like" activity objects that got stored incorrectly
  181. // for a couple of months prior to 9-Jun-2011 and generated bad XML.
  182. // we can probably remove this hack here and in the following function in a few months time.
  183. if(strstr($r->link,'&') && (! strstr($r->link,'&amp;')))
  184. $r->link = str_replace('&','&amp;', $r->link);
  185. $r->link = preg_replace('/\<link(.*?)\"\>/','<link$1"/>',$r->link);
  186. $o .= $r->link;
  187. }
  188. else
  189. $o .= '<link rel="alternate" type="text/html" href="' . xmlify($r->link) . '" />' . "\r\n";
  190. }
  191. if($r->content)
  192. $o .= '<content type="html" >' . xmlify(bbcode($r->content)) . '</content>' . "\r\n";
  193. $o .= '</as:object>' . "\r\n";
  194. return $o;
  195. }
  196. return '';
  197. }
  198. function construct_activity_target($item) {
  199. if($item['target']) {
  200. $o = '<as:target>' . "\r\n";
  201. $r = parse_xml_string($item['target'],false);
  202. if(! $r)
  203. return '';
  204. if($r->type)
  205. $o .= '<as:object-type>' . xmlify($r->type) . '</as:object-type>' . "\r\n";
  206. if($r->id)
  207. $o .= '<id>' . xmlify($r->id) . '</id>' . "\r\n";
  208. if($r->title)
  209. $o .= '<title>' . xmlify($r->title) . '</title>' . "\r\n";
  210. if($r->link) {
  211. if(substr($r->link,0,1) === '<') {
  212. if(strstr($r->link,'&') && (! strstr($r->link,'&amp;')))
  213. $r->link = str_replace('&','&amp;', $r->link);
  214. $r->link = preg_replace('/\<link(.*?)\"\>/','<link$1"/>',$r->link);
  215. $o .= $r->link;
  216. }
  217. else
  218. $o .= '<link rel="alternate" type="text/html" href="' . xmlify($r->link) . '" />' . "\r\n";
  219. }
  220. if($r->content)
  221. $o .= '<content type="html" >' . xmlify(bbcode($r->content)) . '</content>' . "\r\n";
  222. $o .= '</as:target>' . "\r\n";
  223. return $o;
  224. }
  225. return '';
  226. }
  227. function get_atom_elements($feed,$item) {
  228. require_once('library/HTMLPurifier.auto.php');
  229. require_once('include/html2bbcode.php');
  230. $best_photo = array();
  231. $res = array();
  232. $author = $item->get_author();
  233. if($author) {
  234. $res['author-name'] = unxmlify($author->get_name());
  235. $res['author-link'] = unxmlify($author->get_link());
  236. }
  237. else {
  238. $res['author-name'] = unxmlify($feed->get_title());
  239. $res['author-link'] = unxmlify($feed->get_permalink());
  240. }
  241. $res['uri'] = unxmlify($item->get_id());
  242. $res['title'] = unxmlify($item->get_title());
  243. $res['body'] = unxmlify($item->get_content());
  244. $res['plink'] = unxmlify($item->get_link(0));
  245. if($res['plink'])
  246. $base_url = implode('/', array_slice(explode('/',$res['plink']),0,3));
  247. else
  248. $base_url = '';
  249. // look for a photo. We should check media size and find the best one,
  250. // but for now let's just find any author photo
  251. $rawauthor = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
  252. if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
  253. $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
  254. foreach($base as $link) {
  255. if(!x($res, 'author-avatar') || !$res['author-avatar']) {
  256. if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
  257. $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
  258. }
  259. }
  260. }
  261. $rawactor = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor');
  262. if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['object-type'][0]['data'],ACTIVITY_OBJ_PERSON)) {
  263. $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
  264. if($base && count($base)) {
  265. foreach($base as $link) {
  266. if($link['attribs']['']['rel'] === 'alternate' && (! $res['author-link']))
  267. $res['author-link'] = unxmlify($link['attribs']['']['href']);
  268. if(!x($res, 'author-avatar') || !$res['author-avatar']) {
  269. if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
  270. $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
  271. }
  272. }
  273. }
  274. }
  275. // No photo/profile-link on the item - look at the feed level
  276. if((! (x($res,'author-link'))) || (! (x($res,'author-avatar')))) {
  277. $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
  278. if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
  279. $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
  280. foreach($base as $link) {
  281. if($link['attribs']['']['rel'] === 'alternate' && (! $res['author-link']))
  282. $res['author-link'] = unxmlify($link['attribs']['']['href']);
  283. if(! $res['author-avatar']) {
  284. if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
  285. $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
  286. }
  287. }
  288. }
  289. $rawactor = $feed->get_feed_tags(NAMESPACE_ACTIVITY, 'subject');
  290. if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['object-type'][0]['data'],ACTIVITY_OBJ_PERSON)) {
  291. $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
  292. if($base && count($base)) {
  293. foreach($base as $link) {
  294. if($link['attribs']['']['rel'] === 'alternate' && (! $res['author-link']))
  295. $res['author-link'] = unxmlify($link['attribs']['']['href']);
  296. if(! (x($res,'author-avatar'))) {
  297. if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
  298. $res['author-avatar'] = unxmlify($link['attribs']['']['href']);
  299. }
  300. }
  301. }
  302. }
  303. }
  304. $apps = $item->get_item_tags(NAMESPACE_STATUSNET,'notice_info');
  305. if($apps && $apps[0]['attribs']['']['source']) {
  306. $res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source']));
  307. if($res['app'] === 'web')
  308. $res['app'] = 'OStatus';
  309. }
  310. // base64 encoded json structure representing Diaspora signature
  311. $dsig = $item->get_item_tags(NAMESPACE_DFRN,'diaspora_signature');
  312. if($dsig) {
  313. $res['dsprsig'] = unxmlify($dsig[0]['data']);
  314. }
  315. $dguid = $item->get_item_tags(NAMESPACE_DFRN,'diaspora_guid');
  316. if($dguid)
  317. $res['guid'] = unxmlify($dguid[0]['data']);
  318. $bm = $item->get_item_tags(NAMESPACE_DFRN,'bookmark');
  319. if($bm)
  320. $res['bookmark'] = ((unxmlify($bm[0]['data']) === 'true') ? 1 : 0);
  321. /**
  322. * If there's a copy of the body content which is guaranteed to have survived mangling in transit, use it.
  323. */
  324. $have_real_body = false;
  325. $rawenv = $item->get_item_tags(NAMESPACE_DFRN, 'env');
  326. if($rawenv) {
  327. $have_real_body = true;
  328. $res['body'] = $rawenv[0]['data'];
  329. $res['body'] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$res['body']);
  330. // make sure nobody is trying to sneak some html tags by us
  331. $res['body'] = notags(base64url_decode($res['body']));
  332. }
  333. $maxlen = get_max_import_size();
  334. if($maxlen && (strlen($res['body']) > $maxlen))
  335. $res['body'] = substr($res['body'],0, $maxlen);
  336. // It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust
  337. // the content type. Our own network only emits text normally, though it might have been converted to
  338. // html if we used a pubsubhubbub transport. But if we see even one html tag in our text, we will
  339. // have to assume it is all html and needs to be purified.
  340. // It doesn't matter all that much security wise - because before this content is used anywhere, we are
  341. // going to escape any tags we find regardless, but this lets us import a limited subset of html from
  342. // the wild, by sanitising it and converting supported tags to bbcode before we rip out any remaining
  343. // html.
  344. if((strpos($res['body'],'<') !== false) && (strpos($res['body'],'>') !== false)) {
  345. $res['body'] = reltoabs($res['body'],$base_url);
  346. $res['body'] = html2bb_video($res['body']);
  347. $res['body'] = oembed_html2bbcode($res['body']);
  348. $config = HTMLPurifier_Config::createDefault();
  349. $config->set('Cache.DefinitionImpl', null);
  350. // we shouldn't need a whitelist, because the bbcode converter
  351. // will strip out any unsupported tags.
  352. $purifier = new HTMLPurifier($config);
  353. $res['body'] = $purifier->purify($res['body']);
  354. $res['body'] = @html2bbcode($res['body']);
  355. }
  356. elseif(! $have_real_body) {
  357. // it's not one of our messages and it has no tags
  358. // so it's probably just text. We'll escape it just to be safe.
  359. $res['body'] = escape_tags($res['body']);
  360. }
  361. // this tag is obsolete but we keep it for really old sites
  362. $allow = $item->get_item_tags(NAMESPACE_DFRN,'comment-allow');
  363. if($allow && $allow[0]['data'] == 1)
  364. $res['last-child'] = 1;
  365. else
  366. $res['last-child'] = 0;
  367. $private = $item->get_item_tags(NAMESPACE_DFRN,'private');
  368. if($private && $private[0]['data'] == 1)
  369. $res['private'] = 1;
  370. else
  371. $res['private'] = 0;
  372. $extid = $item->get_item_tags(NAMESPACE_DFRN,'extid');
  373. if($extid && $extid[0]['data'])
  374. $res['extid'] = $extid[0]['data'];
  375. $rawlocation = $item->get_item_tags(NAMESPACE_DFRN, 'location');
  376. if($rawlocation)
  377. $res['location'] = unxmlify($rawlocation[0]['data']);
  378. $rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'published');
  379. if($rawcreated)
  380. $res['created'] = unxmlify($rawcreated[0]['data']);
  381. $rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'updated');
  382. if($rawedited)
  383. $res['edited'] = unxmlify($rawedited[0]['data']);
  384. if((x($res,'edited')) && (! (x($res,'created'))))
  385. $res['created'] = $res['edited'];
  386. if(! $res['created'])
  387. $res['created'] = $item->get_date('c');
  388. if(! $res['edited'])
  389. $res['edited'] = $item->get_date('c');
  390. // Disallow time travelling posts
  391. $d1 = strtotime($res['created']);
  392. $d2 = strtotime($res['edited']);
  393. $d3 = strtotime('now');
  394. if($d1 > $d3)
  395. $res['created'] = datetime_convert();
  396. if($d2 > $d3)
  397. $res['edited'] = datetime_convert();
  398. $rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner');
  399. if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])
  400. $res['owner-name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']);
  401. elseif($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data'])
  402. $res['owner-name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']);
  403. if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])
  404. $res['owner-link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']);
  405. elseif($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data'])
  406. $res['owner-link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']);
  407. if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
  408. $base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
  409. foreach($base as $link) {
  410. if(!x($res, 'owner-avatar') || !$res['owner-avatar']) {
  411. if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
  412. $res['owner-avatar'] = unxmlify($link['attribs']['']['href']);
  413. }
  414. }
  415. }
  416. $rawgeo = $item->get_item_tags(NAMESPACE_GEORSS,'point');
  417. if($rawgeo)
  418. $res['coord'] = unxmlify($rawgeo[0]['data']);
  419. $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb');
  420. // select between supported verbs
  421. if($rawverb) {
  422. $res['verb'] = unxmlify($rawverb[0]['data']);
  423. }
  424. // translate OStatus unfollow to activity streams if it happened to get selected
  425. if((x($res,'verb')) && ($res['verb'] === 'http://ostatus.org/schema/1.0/unfollow'))
  426. $res['verb'] = ACTIVITY_UNFOLLOW;
  427. $cats = $item->get_categories();
  428. if($cats) {
  429. $tag_arr = array();
  430. foreach($cats as $cat) {
  431. $term = $cat->get_term();
  432. if(! $term)
  433. $term = $cat->get_label();
  434. $scheme = $cat->get_scheme();
  435. if($scheme && $term && stristr($scheme,'X-DFRN:'))
  436. $tag_arr[] = substr($scheme,7,1) . '[url=' . unxmlify(substr($scheme,9)) . ']' . unxmlify($term) . '[/url]';
  437. elseif($term)
  438. $tag_arr[] = notags(trim($term));
  439. }
  440. $res['tag'] = implode(',', $tag_arr);
  441. }
  442. $attach = $item->get_enclosures();
  443. if($attach) {
  444. $att_arr = array();
  445. foreach($attach as $att) {
  446. $len = intval($att->get_length());
  447. $link = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_link()))));
  448. $title = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_title()))));
  449. $type = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_type()))));
  450. if(strpos($type,';'))
  451. $type = substr($type,0,strpos($type,';'));
  452. if((! $link) || (strpos($link,'http') !== 0))
  453. continue;
  454. if(! $title)
  455. $title = ' ';
  456. if(! $type)
  457. $type = 'application/octet-stream';
  458. $att_arr[] = '[attach]href="' . $link . '" length="' . $len . '" type="' . $type . '" title="' . $title . '"[/attach]';
  459. }
  460. $res['attach'] = implode(',', $att_arr);
  461. }
  462. $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
  463. if($rawobj) {
  464. $res['object'] = '<object>' . "\n";
  465. $child = $rawobj[0]['child'];
  466. if($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) {
  467. $res['object-type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'];
  468. $res['object'] .= '<type>' . $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'] . '</type>' . "\n";
  469. }
  470. if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'])
  471. $res['object'] .= '<id>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'] . '</id>' . "\n";
  472. if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link'])
  473. $res['object'] .= '<link>' . encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) . '</link>' . "\n";
  474. if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'])
  475. $res['object'] .= '<title>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'] . '</title>' . "\n";
  476. if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
  477. $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
  478. if(! $body)
  479. $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
  480. // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
  481. $res['object'] .= '<orig>' . xmlify($body) . '</orig>' . "\n";
  482. if((strpos($body,'<') !== false) || (strpos($body,'>') !== false