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.

720 lines
20 KiB

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
11 years ago
11 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
  1. <?php
  2. require_once('library/HTML5/Parser.php');
  3. require_once('include/crypto.php');
  4. if(! function_exists('scrape_dfrn')) {
  5. function scrape_dfrn($url) {
  6. $a = get_app();
  7. $ret = array();
  8. logger('scrape_dfrn: url=' . $url);
  9. $s = fetch_url($url);
  10. if(! $s)
  11. return $ret;
  12. $headers = $a->get_curl_headers();
  13. logger('scrape_dfrn: headers=' . $headers, LOGGER_DEBUG);
  14. $lines = explode("\n",$headers);
  15. if(count($lines)) {
  16. foreach($lines as $line) {
  17. // don't try and run feeds through the html5 parser
  18. if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml'))))
  19. return ret;
  20. }
  21. }
  22. try {
  23. $dom = HTML5_Parser::parse($s);
  24. } catch (DOMException $e) {
  25. logger('scrape_dfrn: parse error: ' . $e);
  26. }
  27. if(! $dom)
  28. return $ret;
  29. $items = $dom->getElementsByTagName('link');
  30. // get DFRN link elements
  31. foreach($items as $item) {
  32. $x = $item->getAttribute('rel');
  33. if(($x === 'alternate') && ($item->getAttribute('type') === 'application/atom+xml'))
  34. $ret['feed_atom'] = $item->getAttribute('href');
  35. if(substr($x,0,5) == "dfrn-") {
  36. $ret[$x] = $item->getAttribute('href');
  37. }
  38. if($x === 'lrdd') {
  39. $decoded = urldecode($item->getAttribute('href'));
  40. if(preg_match('/acct:([^@]*)@/',$decoded,$matches))
  41. $ret['nick'] = $matches[1];
  42. }
  43. }
  44. // Pull out hCard profile elements
  45. $largest_photo = 0;
  46. $items = $dom->getElementsByTagName('*');
  47. foreach($items as $item) {
  48. if(attribute_contains($item->getAttribute('class'), 'vcard')) {
  49. $level2 = $item->getElementsByTagName('*');
  50. foreach($level2 as $x) {
  51. if(attribute_contains($x->getAttribute('class'),'fn')) {
  52. $ret['fn'] = $x->textContent;
  53. }
  54. if((attribute_contains($x->getAttribute('class'),'photo'))
  55. || (attribute_contains($x->getAttribute('class'),'avatar'))) {
  56. $size = intval($x->getAttribute('width'));
  57. // dfrn prefers 175, so if we find this, we set largest_size so it can't be topped.
  58. if(($size > $largest_photo) || ($size == 175) || (! $largest_photo)) {
  59. $ret['photo'] = $x->getAttribute('src');
  60. $largest_photo = (($size == 175) ? 9999 : $size);
  61. }
  62. }
  63. if(attribute_contains($x->getAttribute('class'),'key')) {
  64. $ret['key'] = $x->textContent;
  65. }
  66. }
  67. }
  68. }
  69. return $ret;
  70. }}
  71. if(! function_exists('validate_dfrn')) {
  72. function validate_dfrn($a) {
  73. $errors = 0;
  74. if(! x($a,'key'))
  75. $errors ++;
  76. if(! x($a,'dfrn-request'))
  77. $errors ++;
  78. if(! x($a,'dfrn-confirm'))
  79. $errors ++;
  80. if(! x($a,'dfrn-notify'))
  81. $errors ++;
  82. if(! x($a,'dfrn-poll'))
  83. $errors ++;
  84. return $errors;
  85. }}
  86. if(! function_exists('scrape_meta')) {
  87. function scrape_meta($url) {
  88. $a = get_app();
  89. $ret = array();
  90. logger('scrape_meta: url=' . $url);
  91. $s = fetch_url($url);
  92. if(! $s)
  93. return $ret;
  94. $headers = $a->get_curl_headers();
  95. logger('scrape_meta: headers=' . $headers, LOGGER_DEBUG);
  96. $lines = explode("\n",$headers);
  97. if(count($lines)) {
  98. foreach($lines as $line) {
  99. // don't try and run feeds through the html5 parser
  100. if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml'))))
  101. return ret;
  102. }
  103. }
  104. try {
  105. $dom = HTML5_Parser::parse($s);
  106. } catch (DOMException $e) {
  107. logger('scrape_meta: parse error: ' . $e);
  108. }
  109. if(! $dom)
  110. return $ret;
  111. $items = $dom->getElementsByTagName('meta');
  112. // get DFRN link elements
  113. foreach($items as $item) {
  114. $x = $item->getAttribute('name');
  115. if(substr($x,0,5) == "dfrn-")
  116. $ret[$x] = $item->getAttribute('content');
  117. }
  118. return $ret;
  119. }}
  120. if(! function_exists('scrape_vcard')) {
  121. function scrape_vcard($url) {
  122. $a = get_app();
  123. $ret = array();
  124. logger('scrape_vcard: url=' . $url);
  125. $s = fetch_url($url);
  126. if(! $s)
  127. return $ret;
  128. $headers = $a->get_curl_headers();
  129. $lines = explode("\n",$headers);
  130. if(count($lines)) {
  131. foreach($lines as $line) {
  132. // don't try and run feeds through the html5 parser
  133. if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml'))))
  134. return ret;
  135. }
  136. }
  137. try {
  138. $dom = HTML5_Parser::parse($s);
  139. } catch (DOMException $e) {
  140. logger('scrape_vcard: parse error: ' . $e);
  141. }
  142. if(! $dom)
  143. return $ret;
  144. // Pull out hCard profile elements
  145. $largest_photo = 0;
  146. $items = $dom->getElementsByTagName('*');
  147. foreach($items as $item) {
  148. if(attribute_contains($item->getAttribute('class'), 'vcard')) {
  149. $level2 = $item->getElementsByTagName('*');
  150. foreach($level2 as $x) {
  151. if(attribute_contains($x->getAttribute('class'),'fn'))
  152. $ret['fn'] = $x->textContent;
  153. if((attribute_contains($x->getAttribute('class'),'photo'))
  154. || (attribute_contains($x->getAttribute('class'),'avatar'))) {
  155. $size = intval($x->getAttribute('width'));
  156. if(($size > $largest_photo) || (! $largest_photo)) {
  157. $ret['photo'] = $x->getAttribute('src');
  158. $largest_photo = $size;
  159. }
  160. }
  161. if((attribute_contains($x->getAttribute('class'),'nickname'))
  162. || (attribute_contains($x->getAttribute('class'),'uid'))) {
  163. $ret['nick'] = $x->textContent;
  164. }
  165. }
  166. }
  167. }
  168. return $ret;
  169. }}
  170. if(! function_exists('scrape_feed')) {
  171. function scrape_feed($url) {
  172. $a = get_app();
  173. $ret = array();
  174. $s = fetch_url($url);
  175. $headers = $a->get_curl_headers();
  176. $code = $a->get_curl_code();
  177. logger('scrape_feed: returns: ' . $code . ' headers=' . $headers, LOGGER_DEBUG);
  178. if(! $s) {
  179. logger('scrape_feed: no data returned for ' . $url);
  180. return $ret;
  181. }
  182. $lines = explode("\n",$headers);
  183. if(count($lines)) {
  184. foreach($lines as $line) {
  185. if(stristr($line,'content-type:')) {
  186. if(stristr($line,'application/atom+xml') || stristr($s,'<feed')) {
  187. $ret['feed_atom'] = $url;
  188. return $ret;
  189. }
  190. if(stristr($line,'application/rss+xml') || stristr($s,'<rss')) {
  191. $ret['feed_rss'] = $url;
  192. return $ret;
  193. }
  194. }
  195. }
  196. // perhaps an RSS version 1 feed with a generic or incorrect content-type?
  197. if(stristr($s,'</item>')) {
  198. $ret['feed_rss'] = $url;
  199. return $ret;
  200. }
  201. }
  202. try {
  203. $dom = HTML5_Parser::parse($s);
  204. } catch (DOMException $e) {
  205. logger('scrape_feed: parse error: ' . $e);
  206. }
  207. if(! $dom) {
  208. logger('scrape_feed: failed to parse.');
  209. return $ret;
  210. }
  211. $head = $dom->getElementsByTagName('base');
  212. if($head) {
  213. foreach($head as $head0) {
  214. $basename = $head0->getAttribute('href');
  215. break;
  216. }
  217. }
  218. if(! $basename)
  219. $basename = substr($url,0,strrpos($url,'/')) . '/';
  220. $items = $dom->getElementsByTagName('link');
  221. // get Atom/RSS link elements, take the first one of either.
  222. if($items) {
  223. foreach($items as $item) {
  224. $x = $item->getAttribute('rel');
  225. if(($x === 'alternate') && ($item->getAttribute('type') === 'application/atom+xml')) {
  226. if(! x($ret,'feed_atom'))
  227. $ret['feed_atom'] = $item->getAttribute('href');
  228. }
  229. if(($x === 'alternate') && ($item->getAttribute('type') === 'application/rss+xml')) {
  230. if(! x($ret,'feed_rss'))
  231. $ret['feed_rss'] = $item->getAttribute('href');
  232. }
  233. }
  234. }
  235. // Drupal and perhaps others only provide relative URL's. Turn them into absolute.
  236. if(x($ret,'feed_atom') && (! strstr($ret['feed_atom'],'://')))
  237. $ret['feed_atom'] = $basename . $ret['feed_atom'];
  238. if(x($ret,'feed_rss') && (! strstr($ret['feed_rss'],'://')))
  239. $ret['feed_rss'] = $basename . $ret['feed_rss'];
  240. return $ret;
  241. }}
  242. /**
  243. *
  244. * Probe a network address to discover what kind of protocols we need to communicate with it.
  245. *
  246. * Warning: this function is a bit touchy and there are some subtle dependencies within the logic flow.
  247. * Edit with care.
  248. *
  249. */
  250. /**
  251. *
  252. * PROBE_DIASPORA has a bias towards returning Diaspora information
  253. * while PROBE_NORMAL has a bias towards dfrn/zot - in the case where
  254. * an address (such as a Friendica address) supports more than one type
  255. * of network.
  256. *
  257. */
  258. define ( 'PROBE_NORMAL', 0);
  259. define ( 'PROBE_DIASPORA', 1);
  260. function probe_url($url, $mode = PROBE_NORMAL) {
  261. require_once('include/email.php');
  262. $result = array();
  263. if(! $url)
  264. return $result;
  265. $network = null;
  266. $diaspora = false;
  267. $diaspora_base = '';
  268. $diaspora_guid = '';
  269. $diaspora_key = '';
  270. $has_lrdd = false;
  271. $email_conversant = false;
  272. $twitter = ((strpos($url,'twitter.com') !== false) ? true : false);
  273. $at_addr = ((strpos($url,'@') !== false) ? true : false);
  274. if(! $twitter) {
  275. if(strpos($url,'mailto:') !== false && $at_addr) {
  276. $url = str_replace('mailto:','',$url);
  277. $links = array();
  278. }
  279. else
  280. $links = lrdd($url);
  281. if(count($links)) {
  282. $has_lrdd = true;
  283. logger('probe_url: found lrdd links: ' . print_r($links,true), LOGGER_DATA);
  284. foreach($links as $link) {
  285. if($link['@attributes']['rel'] === NAMESPACE_ZOT)
  286. $zot = unamp($link['@attributes']['href']);
  287. if($link['@attributes']['rel'] === NAMESPACE_DFRN)
  288. $dfrn = unamp($link['@attributes']['href']);
  289. if($link['@attributes']['rel'] === 'salmon')
  290. $notify = unamp($link['@attributes']['href']);
  291. if($link['@attributes']['rel'] === NAMESPACE_FEED)
  292. $poll = unamp($link['@attributes']['href']);
  293. if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard')
  294. $hcard = unamp($link['@attributes']['href']);
  295. if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page')
  296. $profile = unamp($link['@attributes']['href']);
  297. if($link['@attributes']['rel'] === 'http://portablecontacts.net/spec/1.0')
  298. $poco = unamp($link['@attributes']['href']);
  299. if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location') {
  300. $diaspora_base = unamp($link['@attributes']['href']);
  301. $diaspora = true;
  302. }
  303. if($link['@attributes']['rel'] === 'http://joindiaspora.com/guid') {
  304. $diaspora_guid = unamp($link['@attributes']['href']);
  305. $diaspora = true;
  306. }
  307. if($link['@attributes']['rel'] === 'diaspora-public-key') {
  308. $diaspora_key = base64_decode(unamp($link['@attributes']['href']));
  309. $pubkey = rsatopem($diaspora_key);
  310. $diaspora = true;
  311. }
  312. }
  313. // Status.Net can have more than one profile URL. We need to match the profile URL
  314. // to a contact on incoming messages to prevent spam, and we won't know which one
  315. // to match. So in case of two, one of them is stored as an alias. Only store URL's
  316. // and not webfinger user@host aliases. If they've got more than two non-email style
  317. // aliases, let's hope we're lucky and get one that matches the feed author-uri because
  318. // otherwise we're screwed.
  319. foreach($links as $link) {
  320. if($link['@attributes']['rel'] === 'alias') {
  321. if(strpos($link['@attributes']['href'],'@') === false) {
  322. if(isset($profile)) {
  323. if($link['@attributes']['href'] !== $profile)
  324. $alias = unamp($link['@attributes']['href']);
  325. }
  326. else
  327. $profile = unamp($link['@attributes']['href']);
  328. }
  329. }
  330. }
  331. }
  332. elseif($mode == PROBE_NORMAL) {
  333. // Check email
  334. $orig_url = $url;
  335. if((strpos($orig_url,'@')) && validate_email($orig_url)) {
  336. $x = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1",
  337. intval(local_user())
  338. );
  339. $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1",
  340. intval(local_user())
  341. );
  342. if(count($x) && count($r)) {
  343. $mailbox = construct_mailbox_name($r[0]);
  344. $password = '';
  345. openssl_private_decrypt(hex2bin($r[0]['pass']),$password,$x[0]['prvkey']);
  346. $mbox = email_connect($mailbox,$r[0]['user'],$password);
  347. unset($password);
  348. }
  349. if($mbox) {
  350. $msgs = email_poll($mbox,$orig_url);
  351. if(count($msgs)) {
  352. $addr = $orig_url;
  353. $network = NETWORK_MAIL;
  354. $name = substr($url,0,strpos($url,'@'));
  355. $phost = substr($url,strpos($url,'@')+1);
  356. $profile = 'http://' . $phost;
  357. // fix nick character range
  358. $vcard = array('fn' => $name, 'nick' => $name, 'photo' => gravatar_img($url));
  359. $notify = 'smtp ' . random_string();
  360. $poll = 'email ' . random_string();
  361. $priority = 0;
  362. $x = email_msg_meta($mbox,$msgs[0]);
  363. if(stristr($x->from,$orig_url))
  364. $adr = imap_rfc822_parse_adrlist($x->from,'');
  365. elseif(stristr($x->to,$orig_url))
  366. $adr = imap_rfc822_parse_adrlist($x->to,'');
  367. if(isset($adr)) {
  368. foreach($adr as $feadr) {
  369. if((strcasecmp($feadr->mailbox,$name) == 0)
  370. &&(strcasecmp($feadr->host,$phost) == 0)
  371. && (strlen($feadr->personal))) {
  372. $personal = imap_mime_header_decode($feadr->personal);
  373. $vcard['fn'] = "";
  374. foreach($personal as $perspart)
  375. if ($perspart->charset != "default")
  376. $vcard['fn'] .= iconv($perspart->charset, 'UTF-8//IGNORE', $perspart->text);
  377. else
  378. $vcard['fn'] .= $perspart->text;
  379. $vcard['fn'] = notags($vcard['fn']);
  380. }
  381. }
  382. }
  383. }
  384. imap_close($mbox);
  385. }
  386. }
  387. }
  388. }
  389. if($mode == PROBE_NORMAL) {
  390. if(strlen($zot)) {
  391. $s = fetch_url($zot);
  392. if($s) {
  393. $j = json_decode($s);
  394. if($j) {
  395. $network = NETWORK_ZOT;
  396. $vcard = array(
  397. 'fn' => $j->fullname,
  398. 'nick' => $j->nickname,
  399. 'photo' => $j->photo
  400. );
  401. $profile = $j->url;
  402. $notify = $j->post;
  403. $pubkey = $j->pubkey;
  404. $poll = 'N/A';
  405. }
  406. }
  407. }
  408. if(strlen($dfrn)) {
  409. $ret = scrape_dfrn(($hcard) ? $hcard : $dfrn);
  410. if(is_array($ret) && x($ret,'dfrn-request')) {
  411. $network = NETWORK_DFRN;
  412. $request = $ret['dfrn-request'];
  413. $confirm = $ret['dfrn-confirm'];
  414. $notify = $ret['dfrn-notify'];
  415. $poll = $ret['dfrn-poll'];
  416. $vcard = array();
  417. $vcard['fn'] = $ret['fn'];
  418. $vcard['nick'] = $ret['nick'];
  419. $vcard['photo'] = $ret['photo'];
  420. }
  421. }
  422. }
  423. if($diaspora && $diaspora_base && $diaspora_guid) {
  424. if($mode == PROBE_DIASPORA || ! $notify) {
  425. $notify = $diaspora_base . 'receive/users/' . $diaspora_guid;
  426. $batch = $diaspora_base . 'receive/public' ;
  427. }
  428. if(strpos($url,'@'))
  429. $addr = str_replace('acct:', '', $url);
  430. }
  431. if($network !== NETWORK_ZOT && $network !== NETWORK_DFRN && $network !== NETWORK_MAIL) {
  432. if($diaspora)
  433. $network = NETWORK_DIASPORA;
  434. elseif($has_lrdd)
  435. $network = NETWORK_OSTATUS;
  436. $priority = 0;
  437. if($hcard && ! $vcard) {
  438. $vcard = scrape_vcard($hcard);
  439. // Google doesn't use absolute url in profile photos
  440. if((x($vcard,'photo')) && substr($vcard['photo'],0,1) == '/') {
  441. $h = @parse_url($hcard);
  442. if($h)
  443. $vcard['photo'] = $h['scheme'] . '://' . $h['host'] . $vcard['photo'];
  444. }
  445. logger('probe_url: scrape_vcard: ' . print_r($vcard,true), LOGGER_DATA);
  446. }
  447. if($twitter) {
  448. logger('twitter: setup');
  449. $tid = basename($url);
  450. $tapi = 'https://api.twitter.com/1/statuses/user_timeline.rss';
  451. if(intval($tid))
  452. $poll = $tapi . '?user_id=' . $tid;
  453. else
  454. $poll = $tapi . '?screen_name=' . $tid;
  455. $profile = 'http://twitter.com/#!/' . $tid;
  456. $vcard['photo'] = 'https://api.twitter.com/1/users/profile_image/' . $tid;
  457. $vcard['nick'] = $tid;
  458. $vcard['fn'] = $tid . '@twitter';
  459. }
  460. if(! x($vcard,'fn'))
  461. if(x($vcard,'nick'))
  462. $vcard['fn'] = $vcard['nick'];
  463. $check_feed = false;
  464. if($twitter || ! $poll)
  465. $check_feed = true;
  466. if((! isset($vcard)) || (! x($vcard,'fn')) || (! $profile))
  467. $check_feed = true;
  468. if(($at_addr) && (! count($links)))
  469. $check_feed = false;
  470. if($check_feed) {
  471. $feedret = scrape_feed(($poll) ? $poll : $url);
  472. logger('probe_url: scrape_feed ' . (($poll)? $poll : $url) . ' returns: ' . print_r($feedret,true), LOGGER_DATA);
  473. if(count($feedret) && ($feedret['feed_atom'] || $feedret['feed_rss'])) {
  474. $poll = ((x($feedret,'feed_atom')) ? unamp($feedret['feed_atom']) : unamp($feedret['feed_rss']));
  475. if(! x($vcard))
  476. $vcard = array();
  477. }
  478. if(x($feedret,'photo') && (! x($vcard,'photo')))
  479. $vcard['photo'] = $feedret['photo'];
  480. require_once('library/simplepie/simplepie.inc');
  481. $feed = new SimplePie();
  482. $xml = fetch_url($poll);
  483. logger('probe_url: fetch feed: ' . $poll . ' returns: ' . $xml, LOGGER_DATA);
  484. $a = get_app();
  485. logger('probe_url: scrape_feed: headers: ' . $a->get_curl_headers(), $LOGGER_DATA);
  486. $feed->set_raw_data($xml);
  487. $feed->init();
  488. if($feed->error())
  489. logger('probe_url: scrape_feed: Error parsing XML: ' . $feed->error());
  490. if(! x($vcard,'photo'))
  491. $vcard['photo'] = $feed->get_image_url();
  492. $author = $feed->get_author();
  493. if($author) {
  494. $vcard['fn'] = unxmlify(trim($author->get_name()));
  495. if(! $vcard['fn'])
  496. $vcard['fn'] = trim(unxmlify($author->get_email()));
  497. if(strpos($vcard['fn'],'@') !== false)
  498. $vcard['fn'] = substr($vcard['fn'],0,strpos($vcard['fn'],'@'));
  499. $email = unxmlify($author->get_email());
  500. if(! $profile && $author->get_link())
  501. $profile = trim(unxmlify($author->get_link()));
  502. if(! $vcard['photo']) {
  503. $rawtags = $feed->get_feed_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
  504. if($rawtags) {
  505. $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10];
  506. if((x($elems,'link')) && ($elems['link'][0]['attribs']['']['rel'] === 'photo'))
  507. $vcard['photo'] = $elems['link'][0]['attribs']['']['href'];
  508. }
  509. }
  510. }
  511. else {
  512. $item = $feed->get_item(0);
  513. if($item) {
  514. $author = $item->get_author();
  515. if($author) {
  516. $vcard['fn'] = trim(unxmlify($author->get_name()));
  517. if(! $vcard['fn'])
  518. $vcard['fn'] = trim(unxmlify($author->get_email()));
  519. if(strpos($vcard['fn'],'@') !== false)
  520. $vcard['fn'] = substr($vcard['fn'],0,strpos($vcard['fn'],'@'));
  521. $email = unxmlify($author->get_email());
  522. if(! $profile && $author->get_link())
  523. $profile = trim(unxmlify($author->get_link()));
  524. }
  525. if(! $vcard['photo']) {
  526. $rawmedia = $item->get_item_tags('http://search.yahoo.com/mrss/','thumbnail');
  527. if($rawmedia && $rawmedia[0]['attribs']['']['url'])
  528. $vcard['photo'] = unxmlify($rawmedia[0]['attribs']['']['url']);
  529. }
  530. if(! $vcard['photo']) {
  531. $rawtags = $item->get_item_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
  532. if($rawtags) {
  533. $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10];
  534. if((x($elems,'link')) && ($elems['link'][0]['attribs']['']['rel'] === 'photo'))
  535. $vcard['photo'] = $elems['link'][0]['attribs']['']['href'];
  536. }
  537. }
  538. }
  539. }
  540. if((! $vcard['photo']) && strlen($email))
  541. $vcard['photo'] = gravatar_img($email);
  542. if($poll === $profile)
  543. $lnk = $feed->get_permalink();
  544. if(isset($lnk) && strlen($lnk))
  545. $profile = $lnk;
  546. if(! (x($vcard,'fn')))
  547. $vcard['fn'] = notags($feed->get_title());
  548. if(! (x($vcard,'fn')))
  549. $vcard['fn'] = notags($feed->get_description());
  550. if(strpos($vcard['fn'],'Twitter / ') !== false) {
  551. $vcard['fn'] = substr($vcard['fn'],strpos($vcard['fn'],'/')+1);
  552. $vcard['fn'] = trim($vcard['fn']);
  553. }
  554. if(! x($vcard,'nick')) {
  555. $vcard['nick'] = strtolower(notags(unxmlify($vcard['fn'])));
  556. if(strpos($vcard['nick'],' '))
  557. $vcard['nick'] = trim(substr($vcard['nick'],0,strpos($vcard['nick'],' ')));
  558. }
  559. if(! $network)
  560. $network = NETWORK_FEED;
  561. if(! $priority)
  562. $priority = 2;
  563. }
  564. }
  565. if(! x($vcard,'photo')) {
  566. $a = get_app();
  567. $vcard['photo'] = $a->get_baseurl() . '/images/person-175.jpg' ;
  568. }
  569. if(! $profile)
  570. $profile = $url;
  571. // No human could be associated with this link, use the URL as the contact name
  572. if(($network === NETWORK_FEED) && ($poll) && (! x($vcard,'fn')))
  573. $vcard['fn'] = $url;
  574. $vcard['fn'] = notags($vcard['fn']);
  575. $vcard['nick'] = str_replace(' ','',notags($vcard['nick']));
  576. $result['name'] = $vcard['fn'];
  577. $result['nick'] = $vcard['nick'];
  578. $result['url'] = $profile;
  579. $result['addr'] = $addr;
  580. $result['batch'] = $batch;
  581. $result['notify'] = $notify;
  582. $result['poll'] = $poll;
  583. $result['request'] = $request;
  584. $result['confirm'] = $confirm;
  585. $result['poco'] = $poco;
  586. $result['photo'] = $vcard['photo'];
  587. $result['priority'] = $priority;
  588. $result['network'] = $network;
  589. $result['alias'] = $alias;
  590. $result['pubkey'] = $pubkey;
  591. logger('probe_url: ' . print_r($result,true), LOGGER_DEBUG);
  592. return $result;
  593. }