diff --git a/boot.php b/boot.php index 2242ba476..955b89e56 100644 --- a/boot.php +++ b/boot.php @@ -530,6 +530,8 @@ class App { private $cached_profile_image; private $cached_profile_picdate; + private static $a; + /** * @brief App constructor. */ @@ -710,6 +712,8 @@ class App { } } + self::$a = $this; + } function get_basepath() { @@ -734,6 +738,10 @@ class App { function get_baseurl($ssl = false) { + // Is the function called statically? + if (!is_object($this)) + return(self::$a->get_baseurl($ssl)); + $scheme = $this->scheme; if((x($this->config,'system')) && (x($this->config['system'],'ssl_policy'))) { diff --git a/include/Contact.php b/include/Contact.php index f4befd023..86e67bbe8 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -132,8 +132,8 @@ function terminate_friendship($user,$self,$contact) { diaspora_unshare($user,$contact); } elseif($contact['network'] === NETWORK_DFRN) { - require_once('include/items.php'); - dfrn_deliver($user,$contact,'placeholder', 1); + require_once('include/dfrn.php'); + dfrn::deliver($user,$contact,'placeholder', 1); } } @@ -208,15 +208,15 @@ function get_contact_details_by_url($url, $uid = -1) { } // Fetching further contact data from the contact table - $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `addr`, `forum`, `prv`, `bd` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d AND `network` = '%s'", + $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `thumb`, `addr`, `forum`, `prv`, `bd`, `self` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d AND `network` IN ('%s', '')", dbesc(normalise_link($url)), intval($uid), dbesc($profile["network"])); if (!count($r) AND !isset($profile)) - $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `addr`, `forum`, `prv`, `bd` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d", + $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `thumb`, `addr`, `forum`, `prv`, `bd`, `self` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d", dbesc(normalise_link($url)), intval($uid)); if (!count($r) AND !isset($profile)) - $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `addr`, `forum`, `prv`, `bd` FROM `contact` WHERE `nurl` = '%s' AND `uid` = 0", + $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `thumb`, `addr`, `forum`, `prv`, `bd` FROM `contact` WHERE `nurl` = '%s' AND `uid` = 0", dbesc(normalise_link($url))); if ($r) { @@ -228,7 +228,7 @@ function get_contact_details_by_url($url, $uid = -1) { $profile["nick"] = $r[0]["nick"]; if (!isset($profile["addr"]) AND $r[0]["addr"]) $profile["addr"] = $r[0]["addr"]; - if (!isset($profile["photo"]) AND $r[0]["photo"]) + if ((!isset($profile["photo"]) OR $r[0]["self"]) AND $r[0]["photo"]) $profile["photo"] = $r[0]["photo"]; if (!isset($profile["location"]) AND $r[0]["location"]) $profile["location"] = $r[0]["location"]; @@ -246,6 +246,8 @@ function get_contact_details_by_url($url, $uid = -1) { $profile["addr"] = $r[0]["addr"]; if (!isset($profile["bd"]) AND $r[0]["bd"]) $profile["bd"] = $r[0]["bd"]; + if (isset($r[0]["thumb"])) + $profile["thumb"] = $r[0]["thumb"]; if ($r[0]["uid"] == 0) $profile["cid"] = 0; else @@ -665,4 +667,34 @@ function posts_from_contact($a, $contact_id) { return $o; } + +/** + * @brief Returns a formatted location string from the given profile array + * + * @param array $profile Profile array (Generated from the "profile" table) + * + * @return string Location string + */ +function formatted_location($profile) { + $location = ''; + + if($profile['locality']) + $location .= $profile['locality']; + + if($profile['region'] AND ($profile['locality'] != $profile['region'])) { + if($location) + $location .= ', '; + + $location .= $profile['region']; + } + + if($profile['country-name']) { + if($location) + $location .= ', '; + + $location .= $profile['country-name']; + } + + return $location; +} ?> diff --git a/include/cron.php b/include/cron.php index fe4fa46cd..3acf711dd 100644 --- a/include/cron.php +++ b/include/cron.php @@ -30,7 +30,6 @@ function cron_run(&$argv, &$argc){ require_once('include/session.php'); require_once('include/datetime.php'); - require_once('library/simplepie/simplepie.inc'); require_once('include/items.php'); require_once('include/Contact.php'); require_once('include/email.php'); diff --git a/include/delivery.php b/include/delivery.php index a88873361..5ef942dd0 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -5,6 +5,7 @@ require_once('include/html2plain.php'); require_once("include/Scrape.php"); require_once('include/diaspora.php'); require_once("include/ostatus.php"); +require_once("include/dfrn.php"); function delivery_run(&$argv, &$argc){ global $a, $db; @@ -264,8 +265,6 @@ function delivery_run(&$argv, &$argc){ if(count($r)) $contact = $r[0]; - $hubxml = feed_hublinks(); - if($contact['self']) continue; @@ -278,138 +277,54 @@ function delivery_run(&$argv, &$argc){ case NETWORK_DFRN: logger('notifier: '.$target_item["guid"].' dfrndelivery: ' . $contact['name']); - $feed_template = get_markup_template('atom_feed.tpl'); - $mail_template = get_markup_template('atom_mail.tpl'); - - $atom = ''; - - - $birthday = feed_birthday($owner['uid'],$owner['timezone']); - - if(strlen($birthday)) - $birthday = '' . xmlify($birthday) . ''; - - $atom .= replace_macros($feed_template, array( - '$version' => xmlify(FRIENDICA_VERSION), - '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner['nickname'] ), - '$feed_title' => xmlify($owner['name']), - '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', $updated . '+00:00' , ATOM_TIME)) , - '$hub' => $hubxml, - '$salmon' => '', // private feed, we don't use salmon here - '$name' => xmlify($owner['name']), - '$profile_page' => xmlify($owner['url']), - '$photo' => xmlify($owner['photo']), - '$thumb' => xmlify($owner['thumb']), - '$picdate' => xmlify(datetime_convert('UTC','UTC',$owner['avatar-date'] . '+00:00' , ATOM_TIME)) , - '$uridate' => xmlify(datetime_convert('UTC','UTC',$owner['uri-date'] . '+00:00' , ATOM_TIME)) , - '$namdate' => xmlify(datetime_convert('UTC','UTC',$owner['name-date'] . '+00:00' , ATOM_TIME)) , - '$birthday' => $birthday, - '$community' => (($owner['page-flags'] == PAGE_COMMUNITY) ? '1' : '') - )); - - if($mail) { - $public_message = false; // mail is not public - - $body = fix_private_photos($item['body'],$owner['uid'],null,$message[0]['contact-id']); - - $atom .= replace_macros($mail_template, array( - '$name' => xmlify($owner['name']), - '$profile_page' => xmlify($owner['url']), - '$thumb' => xmlify($owner['thumb']), - '$item_id' => xmlify($item['uri']), - '$subject' => xmlify($item['title']), - '$created' => xmlify(datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME)), - '$content' => xmlify($body), - '$parent_id' => xmlify($item['parent-uri']) - )); - } elseif($fsuggest) { - $public_message = false; // suggestions are not public - - $sugg_template = get_markup_template('atom_suggest.tpl'); - - $atom .= replace_macros($sugg_template, array( - '$name' => xmlify($item['name']), - '$url' => xmlify($item['url']), - '$photo' => xmlify($item['photo']), - '$request' => xmlify($item['request']), - '$note' => xmlify($item['note']) - )); - - // We don't need this any more - - q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", - intval($item['id']) - ); - } elseif($relocate) { - $public_message = false; // suggestions are not public - - $sugg_template = get_markup_template('atom_relocate.tpl'); - - /* get site pubkey. this could be a new installation with no site keys*/ - $pubkey = get_config('system','site_pubkey'); - if(! $pubkey) { - $res = new_keypair(1024); - set_config('system','site_prvkey', $res['prvkey']); - set_config('system','site_pubkey', $res['pubkey']); - } - - $rp = q("SELECT `resource-id` , `scale`, type FROM `photo` - WHERE `profile` = 1 AND `uid` = %d ORDER BY scale;", $uid); - $photos = array(); - $ext = Photo::supportedTypes(); - foreach($rp as $p){ - $photos[$p['scale']] = $a->get_baseurl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']]; - } - unset($rp, $ext); - - $atom .= replace_macros($sugg_template, array( - '$name' => xmlify($owner['name']), - '$photo' => xmlify($photos[4]), - '$thumb' => xmlify($photos[5]), - '$micro' => xmlify($photos[6]), - '$url' => xmlify($owner['url']), - '$request' => xmlify($owner['request']), - '$confirm' => xmlify($owner['confirm']), - '$notify' => xmlify($owner['notify']), - '$poll' => xmlify($owner['poll']), - '$sitepubkey' => xmlify(get_config('system','site_pubkey')), - //'$pubkey' => xmlify($owner['pubkey']), - //'$prvkey' => xmlify($owner['prvkey']), - )); - unset($photos); - } elseif($followup) { + if ($mail) { + $item['body'] = fix_private_photos($item['body'],$owner['uid'],null,$message[0]['contact-id']); + $atom = dfrn::mail($item, $owner); + } elseif ($fsuggest) { + $atom = dfrn::fsuggest($item, $owner); + q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id'])); + } elseif ($relocate) + $atom = dfrn::relocate($owner, $uid); + elseif($followup) { + $msgitems = array(); foreach($items as $item) { // there is only one item - if(! $item['parent']) + if(!$item['parent']) continue; if($item['id'] == $item_id) { logger('followup: item: ' . print_r($item,true), LOGGER_DATA); - $atom .= atom_entry($item,'text',null,$owner,false); + $msgitems[] = $item; } } + $atom = dfrn::entries($msgitems,$owner); } else { + $msgitems = array(); foreach($items as $item) { - if(! $item['parent']) + if(!$item['parent']) continue; // private emails may be in included in public conversations. Filter them. - if(($public_message) && $item['private'] == 1) + if(($public_message) && $item['private']) continue; $item_contact = get_item_contact($item,$icontacts); - if(! $item_contact) + if(!$item_contact) continue; if($normal_mode) { - if($item_id == $item['id'] || $item['id'] == $item['parent']) - $atom .= atom_entry($item,'text',null,$owner,true,(($top_level) ? $contact['id'] : 0)); - } else - $atom .= atom_entry($item,'text',null,$owner,true); + if($item_id == $item['id'] || $item['id'] == $item['parent']) { + $item["entry:comment-allow"] = true; + $item["entry:cid"] = (($top_level) ? $contact['id'] : 0); + $msgitems[] = $item; + } + } else { + $item["entry:comment-allow"] = true; + $msgitems[] = $item; + } } + $atom = dfrn::entries($msgitems,$owner); } - $atom .= '' . "\r\n"; - - logger('notifier: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG); + logger('notifier entry: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG); logger('notifier: ' . $atom, LOGGER_DATA); $basepath = implode('/', array_slice(explode('/',$contact['url']),0,3)); @@ -458,7 +373,6 @@ function delivery_run(&$argv, &$argc){ if (($x[0]['page-flags'] == PAGE_SOAPBOX) AND $top_level) break; - require_once('library/simplepie/simplepie.inc'); logger('mod-delivery: local delivery'); local_delivery($x[0],$atom); break; @@ -466,7 +380,7 @@ function delivery_run(&$argv, &$argc){ } if(! was_recently_delayed($contact['id'])) - $deliver_status = dfrn_deliver($owner,$contact,$atom); + $deliver_status = dfrn::deliver($owner,$contact,$atom); else $deliver_status = (-1); diff --git a/include/dfrn.php b/include/dfrn.php new file mode 100644 index 000000000..2c8e8ce38 --- /dev/null +++ b/include/dfrn.php @@ -0,0 +1,1048 @@ +formatOutput = true; + + $root = self::add_header($doc, $owner, "dfrn:owner", "", false); + + if(! count($items)) + return trim($doc->saveXML()); + + foreach($items as $item) { + $entry = self::entry($doc, "text", $item, $owner, $item["entry:comment-allow"], $item["entry:cid"]); + $root->appendChild($entry); + } + + return(trim($doc->saveXML())); + } + + /** + * @brief Generate an atom feed for the given user + * + * This function is called when another server is pulling data from the user feed. + * + * @param string $dfrn_id DFRN ID from the requesting party + * @param string $owner_nick Owner nick name + * @param string $last_update Date of the last update + * @param int $direction Can be -1, 0 or 1. + * + * @return string DFRN feed entries + */ + function feed($dfrn_id, $owner_nick, $last_update, $direction = 0) { + + $a = get_app(); + + $sitefeed = ((strlen($owner_nick)) ? false : true); // not yet implemented, need to rewrite huge chunks of following logic + $public_feed = (($dfrn_id) ? false : true); + $starred = false; // not yet implemented, possible security issues + $converse = false; + + if($public_feed && $a->argc > 2) { + for($x = 2; $x < $a->argc; $x++) { + if($a->argv[$x] == 'converse') + $converse = true; + if($a->argv[$x] == 'starred') + $starred = true; + if($a->argv[$x] === 'category' && $a->argc > ($x + 1) && strlen($a->argv[$x+1])) + $category = $a->argv[$x+1]; + } + } + + + + // default permissions - anonymous user + + $sql_extra = " AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' "; + + $r = q("SELECT `contact`.*, `user`.`uid` AS `user_uid`, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags` + FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` + WHERE `contact`.`self` = 1 AND `user`.`nickname` = '%s' LIMIT 1", + dbesc($owner_nick) + ); + + if(! count($r)) + killme(); + + $owner = $r[0]; + $owner_id = $owner['user_uid']; + $owner_nick = $owner['nickname']; + + $sql_post_table = ""; + $visibility = ""; + + if(! $public_feed) { + + $sql_extra = ''; + switch($direction) { + case (-1): + $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($dfrn_id)); + $my_id = $dfrn_id; + break; + case 0: + $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); + $my_id = '1:' . $dfrn_id; + break; + case 1: + $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); + $my_id = '0:' . $dfrn_id; + break; + default: + return false; + break; // NOTREACHED + } + + $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `contact`.`uid` = %d $sql_extra LIMIT 1", + intval($owner_id) + ); + + if(! count($r)) + killme(); + + $contact = $r[0]; + require_once('include/security.php'); + $groups = init_groups_visitor($contact['id']); + + if(count($groups)) { + for($x = 0; $x < count($groups); $x ++) + $groups[$x] = '<' . intval($groups[$x]) . '>' ; + $gs = implode('|', $groups); + } else + $gs = '<<>>' ; // Impossible to match + + $sql_extra = sprintf(" + AND ( `allow_cid` = '' OR `allow_cid` REGEXP '<%d>' ) + AND ( `deny_cid` = '' OR NOT `deny_cid` REGEXP '<%d>' ) + AND ( `allow_gid` = '' OR `allow_gid` REGEXP '%s' ) + AND ( `deny_gid` = '' OR NOT `deny_gid` REGEXP '%s') + ", + intval($contact['id']), + intval($contact['id']), + dbesc($gs), + dbesc($gs) + ); + } + + if($public_feed) + $sort = 'DESC'; + else + $sort = 'ASC'; + + $date_field = "`changed`"; + $sql_order = "`item`.`parent` ".$sort.", `item`.`created` ASC"; + + if(! strlen($last_update)) + $last_update = 'now -30 days'; + + if(isset($category)) { + $sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", + dbesc(protect_sprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($owner_id)); + //$sql_extra .= file_tag_file_query('item',$category,'category'); + } + + if($public_feed) { + if(! $converse) + $sql_extra .= " AND `contact`.`self` = 1 "; + } + + $check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s'); + + // AND ( `item`.`edited` > '%s' OR `item`.`changed` > '%s' ) + // dbesc($check_date), + + $r = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id`, + `contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`, + `contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`, + `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, + `contact`.`id` AS `contact-id`, `contact`.`uid` AS `contact-uid`, + `sign`.`signed_text`, `sign`.`signature`, `sign`.`signer` + FROM `item` $sql_post_table + INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` + AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 + LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` + WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`parent` != 0 + AND ((`item`.`wall` = 1) $visibility) AND `item`.$date_field > '%s' + $sql_extra + ORDER BY $sql_order LIMIT 0, 300", + intval($owner_id), + dbesc($check_date), + dbesc($sort) + ); + + // Will check further below if this actually returned results. + // We will provide an empty feed if that is the case. + + $items = $r; + + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; + + $alternatelink = $owner['url']; + + if(isset($category)) + $alternatelink .= "/category/".$category; + + if ($public_feed) + $author = "dfrn:owner"; + else + $author = "author"; + + $root = self::add_header($doc, $owner, $author, $alternatelink, true); + + // This hook can't work anymore + // call_hooks('atom_feed', $atom); + + if(! count($items)) { + $atom = trim($doc->saveXML()); + + call_hooks('atom_feed_end', $atom); + + return $atom; + } + + foreach($items as $item) { + + // prevent private email from leaking. + if($item['network'] === NETWORK_MAIL) + continue; + + // public feeds get html, our own nodes use bbcode + + if($public_feed) { + $type = 'html'; + // catch any email that's in a public conversation and make sure it doesn't leak + if($item['private']) + continue; + } else + $type = 'text'; + + $entry = self::entry($doc, $type, $item, $owner, true); + $root->appendChild($entry); + + } + + $atom = trim($doc->saveXML()); + + call_hooks('atom_feed_end', $atom); + + return $atom; + } + + /** + * @brief Create XML text for DFRN mails + * + * @param array $item message elements + * @param array $owner Owner record + * + * @return string DFRN mail + */ + function mail($item, $owner) { + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; + + $root = self::add_header($doc, $owner, "dfrn:owner", "", false); + + $mail = $doc->createElement("dfrn:mail"); + $sender = $doc->createElement("dfrn:sender"); + + xml_add_element($doc, $sender, "dfrn:name", $owner['name']); + xml_add_element($doc, $sender, "dfrn:uri", $owner['url']); + xml_add_element($doc, $sender, "dfrn:avatar", $owner['thumb']); + + $mail->appendChild($sender); + + xml_add_element($doc, $mail, "dfrn:id", $item['uri']); + xml_add_element($doc, $mail, "dfrn:in-reply-to", $item['parent-uri']); + xml_add_element($doc, $mail, "dfrn:sentdate", datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME)); + xml_add_element($doc, $mail, "dfrn:subject", $item['title']); + xml_add_element($doc, $mail, "dfrn:content", $item['body']); + + $root->appendChild($mail); + + return(trim($doc->saveXML())); + } + + /** + * @brief Create XML text for DFRN friend suggestions + * + * @param array $item suggestion elements + * @param array $owner Owner record + * + * @return string DFRN suggestions + */ + function fsuggest($item, $owner) { + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; + + $root = self::add_header($doc, $owner, "dfrn:owner", "", false); + + $suggest = $doc->createElement("dfrn:suggest"); + + xml_add_element($doc, $suggest, "dfrn:url", $item['url']); + xml_add_element($doc, $suggest, "dfrn:name", $item['name']); + xml_add_element($doc, $suggest, "dfrn:photo", $item['photo']); + xml_add_element($doc, $suggest, "dfrn:request", $item['request']); + xml_add_element($doc, $suggest, "dfrn:note", $item['note']); + + $root->appendChild($suggest); + + return(trim($doc->saveXML())); + } + + /** + * @brief Create XML text for DFRN relocations + * + * @param array $owner Owner record + * @param int $uid User ID + * + * @return string DFRN relocations + */ + function relocate($owner, $uid) { + + /* get site pubkey. this could be a new installation with no site keys*/ + $pubkey = get_config('system','site_pubkey'); + if(! $pubkey) { + $res = new_keypair(1024); + set_config('system','site_prvkey', $res['prvkey']); + set_config('system','site_pubkey', $res['pubkey']); + } + + $rp = q("SELECT `resource-id` , `scale`, type FROM `photo` + WHERE `profile` = 1 AND `uid` = %d ORDER BY scale;", $uid); + $photos = array(); + $ext = Photo::supportedTypes(); + + foreach($rp as $p) + $photos[$p['scale']] = app::get_baseurl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']]; + + unset($rp, $ext); + + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; + + $root = self::add_header($doc, $owner, "dfrn:owner", "", false); + + $relocate = $doc->createElement("dfrn:relocate"); + + xml_add_element($doc, $relocate, "dfrn:url", $owner['url']); + xml_add_element($doc, $relocate, "dfrn:name", $owner['name']); + xml_add_element($doc, $relocate, "dfrn:photo", $photos[4]); + xml_add_element($doc, $relocate, "dfrn:thumb", $photos[5]); + xml_add_element($doc, $relocate, "dfrn:micro", $photos[6]); + xml_add_element($doc, $relocate, "dfrn:request", $owner['request']); + xml_add_element($doc, $relocate, "dfrn:confirm", $owner['confirm']); + xml_add_element($doc, $relocate, "dfrn:notify", $owner['notify']); + xml_add_element($doc, $relocate, "dfrn:poll", $owner['poll']); + xml_add_element($doc, $relocate, "dfrn:sitepubkey", get_config('system','site_pubkey')); + + $root->appendChild($relocate); + + return(trim($doc->saveXML())); + } + + /** + * @brief Adds the header elements for the DFRN protocol + * + * @param object $doc XML document + * @param array $owner Owner record + * @param string $authorelement Element name for the author + * @param string $alternatelink link to profile or category + * @param bool $public Is it a header for public posts? + * + * @return object XML root object + */ + private function add_header($doc, $owner, $authorelement, $alternatelink = "", $public = false) { + + if ($alternatelink == "") + $alternatelink = $owner['url']; + + $root = $doc->createElementNS(NS_ATOM, 'feed'); + $doc->appendChild($root); + + $root->setAttribute("xmlns:thr", NS_THR); + $root->setAttribute("xmlns:at", "http://purl.org/atompub/tombstones/1.0"); + $root->setAttribute("xmlns:media", NS_MEDIA); + $root->setAttribute("xmlns:dfrn", "http://purl.org/macgirvin/dfrn/1.0"); + $root->setAttribute("xmlns:activity", NS_ACTIVITY); + $root->setAttribute("xmlns:georss", NS_GEORSS); + $root->setAttribute("xmlns:poco", NS_POCO); + $root->setAttribute("xmlns:ostatus", NS_OSTATUS); + $root->setAttribute("xmlns:statusnet", NS_STATUSNET); + + //xml_add_element($doc, $root, "id", app::get_baseurl()."/profile/".$owner["nick"]); + xml_add_element($doc, $root, "id", app::get_baseurl()."/profile/".$owner["nick"]); + xml_add_element($doc, $root, "title", $owner["name"]); + + $attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION); + xml_add_element($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes); + + $attributes = array("rel" => "license", "href" => "http://creativecommons.org/licenses/by/3.0/"); + xml_add_element($doc, $root, "link", "", $attributes); + + $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $alternatelink); + xml_add_element($doc, $root, "link", "", $attributes); + + ostatus_hublinks($doc, $root); + + if ($public) { + $attributes = array("rel" => "salmon", "href" => app::get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); + + $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => app::get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); + + $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => app::get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); + } + + if ($owner['page-flags'] == PAGE_COMMUNITY) + xml_add_element($doc, $root, "dfrn:community", 1); + + xml_add_element($doc, $root, "updated", datetime_convert("UTC", "UTC", "now", ATOM_TIME)); + + $author = self::add_author($doc, $owner, $authorelement, $public); + $root->appendChild($author); + + return $root; + } + + /** + * @brief Adds the author element in the header for the DFRN protocol + * + * @param object $doc XML document + * @param array $owner Owner record + * @param string $authorelement Element name for the author + * + * @return object XML author object + */ + private function add_author($doc, $owner, $authorelement, $public) { + + $author = $doc->createElement($authorelement); + + $namdate = datetime_convert('UTC', 'UTC', $owner['name-date'].'+00:00' , ATOM_TIME); + $uridate = datetime_convert('UTC', 'UTC', $owner['uri-date'].'+00:00', ATOM_TIME); + $picdate = datetime_convert('UTC', 'UTC', $owner['avatar-date'].'+00:00', ATOM_TIME); + + $attributes = array("dfrn:updated" => $namdate); + xml_add_element($doc, $author, "name", $owner["name"], $attributes); + + $attributes = array("dfrn:updated" => $namdate); + xml_add_element($doc, $author, "uri", app::get_baseurl().'/profile/'.$owner["nickname"], $attributes); + + $attributes = array("dfrn:updated" => $namdate); + xml_add_element($doc, $author, "dfrn:handle", $owner["addr"], $attributes); + + $attributes = array("rel" => "photo", "type" => "image/jpeg", "dfrn:updated" => $picdate, + "media:width" => 175, "media:height" => 175, "href" => $owner['photo']); + xml_add_element($doc, $author, "link", "", $attributes); + + $attributes = array("rel" => "avatar", "type" => "image/jpeg", "dfrn:updated" => $picdate, + "media:width" => 175, "media:height" => 175, "href" => $owner['photo']); + xml_add_element($doc, $author, "link", "", $attributes); + + $birthday = feed_birthday($owner['user_uid'], $owner['timezone']); + + if ($birthday) + xml_add_element($doc, $author, "dfrn:birthday", $birthday); + + // The following fields will only be generated if this isn't for a public feed + if ($public) + return $author; + + // Only show contact details when we are allowed to + $r = q("SELECT `profile`.`about`, `profile`.`name`, `profile`.`homepage`, `user`.`nickname`, `user`.`timezone`, + `profile`.`locality`, `profile`.`region`, `profile`.`country-name`, `profile`.`pub_keywords`, `profile`.`dob` + FROM `profile` + INNER JOIN `user` ON `user`.`uid` = `profile`.`uid` + WHERE `profile`.`is-default` AND NOT `user`.`hidewall` AND `user`.`uid` = %d", + intval($owner['user_uid'])); + if ($r) { + $profile = $r[0]; + xml_add_element($doc, $author, "poco:displayName", $profile["name"]); + xml_add_element($doc, $author, "poco:updated", $namdate); + + if (trim($profile["dob"]) != "0000-00-00") + xml_add_element($doc, $author, "poco:birthday", "0000-".date("m-d", strtotime($profile["dob"]))); + + xml_add_element($doc, $author, "poco:note", $profile["about"]); + xml_add_element($doc, $author, "poco:preferredUsername", $profile["nickname"]); + + $savetz = date_default_timezone_get(); + date_default_timezone_set($profile["timezone"]); + xml_add_element($doc, $author, "poco:utcOffset", date("P")); + date_default_timezone_set($savetz); + + if (trim($profile["homepage"]) != "") { + $urls = $doc->createElement("poco:urls"); + xml_add_element($doc, $urls, "poco:type", "homepage"); + xml_add_element($doc, $urls, "poco:value", $profile["homepage"]); + xml_add_element($doc, $urls, "poco:primary", "true"); + $author->appendChild($urls); + } + + if (trim($profile["pub_keywords"]) != "") { + $keywords = explode(",", $profile["pub_keywords"]); + + foreach ($keywords AS $keyword) + xml_add_element($doc, $author, "poco:tags", trim($keyword)); + + } + + /// @todo When we are having the XMPP address in the profile we should propagate it here + $xmpp = ""; + if (trim($xmpp) != "") { + $ims = $doc->createElement("poco:ims"); + xml_add_element($doc, $ims, "poco:type", "xmpp"); + xml_add_element($doc, $ims, "poco:value", $xmpp); + xml_add_element($doc, $ims, "poco:primary", "true"); + $author->appendChild($ims); + } + + if (trim($profile["locality"].$profile["region"].$profile["country-name"]) != "") { + $element = $doc->createElement("poco:address"); + + xml_add_element($doc, $element, "poco:formatted", formatted_location($profile)); + + if (trim($profile["locality"]) != "") + xml_add_element($doc, $element, "poco:locality", $profile["locality"]); + + if (trim($profile["region"]) != "") + xml_add_element($doc, $element, "poco:region", $profile["region"]); + + if (trim($profile["country-name"]) != "") + xml_add_element($doc, $element, "poco:country", $profile["country-name"]); + + $author->appendChild($element); + } + } + + return $author; + } + + /** + * @brief Adds the author elements in the "entry" elements of the DFRN protocol + * + * @param object $doc XML document + * @param string $element Element name for the author + * @param string $contact_url Link of the contact + * @param array $items Item elements + * + * @return object XML author object + */ + private function add_entry_author($doc, $element, $contact_url, $item) { + + $contact = get_contact_details_by_url($contact_url, $item["uid"]); + + $author = $doc->createElement($element); + xml_add_element($doc, $author, "name", $contact["name"]); + xml_add_element($doc, $author, "uri", $contact["url"]); + xml_add_element($doc, $author, "dfrn:handle", $contact["addr"]); + + /// @Todo + /// - Check real image type and image size + /// - Check which of these boths elements we should use + $attributes = array( + "rel" => "photo", + "type" => "image/jpeg", + "media:width" => 80, + "media:height" => 80, + "href" => $contact["photo"]); + xml_add_element($doc, $author, "link", "", $attributes); + + $attributes = array( + "rel" => "avatar", + "type" => "image/jpeg", + "media:width" => 80, + "media:height" => 80, + "href" => $contact["photo"]); + xml_add_element($doc, $author, "link", "", $attributes); + + return $author; + } + + /** + * @brief Adds the activity elements + * + * @param object $doc XML document + * @param string $element Element name for the activity + * @param string $activity activity value + * + * @return object XML activity object + */ + private function create_activity($doc, $element, $activity) { + + if($activity) { + $entry = $doc->createElement($element); + + $r = parse_xml_string($activity, false); + if(!$r) + return false; + if($r->type) + xml_add_element($doc, $entry, "activity:object-type", $r->type); + if($r->id) + xml_add_element($doc, $entry, "id", $r->id); + if($r->title) + xml_add_element($doc, $entry, "title", $r->title); + if($r->link) { + if(substr($r->link,0,1) === '<') { + if(strstr($r->link,'&') && (! strstr($r->link,'&'))) + $r->link = str_replace('&','&', $r->link); + + $r->link = preg_replace('/\/','',$r->link); + + $data = parse_xml_string($r->link, false); + foreach ($data->attributes() AS $parameter => $value) + $attributes[$parameter] = $value; + } else + $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $r->link); + + xml_add_element($doc, $entry, "link", "", $attributes); + } + if($r->content) + xml_add_element($doc, $entry, "content", bbcode($r->content), array("type" => "html")); + + return $entry; + } + + return false; + } + + /** + * @brief Adds the elements for attachments + * + * @param object $doc XML document + * @param object $root XML root + * @param array $item Item element + * + * @return object XML attachment object + */ + private function get_attachment($doc, $root, $item) { + $arr = explode('[/attach],',$item['attach']); + if(count($arr)) { + foreach($arr as $r) { + $matches = false; + $cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|',$r,$matches); + if($cnt) { + $attributes = array("rel" => "enclosure", + "href" => $matches[1], + "type" => $matches[3]); + + if(intval($matches[2])) + $attributes["length"] = intval($matches[2]); + + if(trim($matches[4]) != "") + $attributes["title"] = trim($matches[4]); + + xml_add_element($doc, $root, "link", "", $attributes); + } + } + } + } + + /** + * @brief Adds the "entry" elements for the DFRN protocol + * + * @param object $doc XML document + * @param string $type "text" or "html" + * @param array $item Item element + * @param array $owner Owner record + * @param bool $comment Trigger the sending of the "comment" element + * @param int $cid Contact ID of the recipient + * + * @return object XML entry object + */ + private function entry($doc, $type, $item, $owner, $comment = false, $cid = 0) { + + $mentioned = array(); + + if(!$item['parent']) + return; + + if($item['deleted']) { + $attributes = array("ref" => $item['uri'], "when" => datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)); + return xml_create_element($doc, "at:deleted-entry", "", $attributes); + } + + $entry = $doc->createElement("entry"); + + 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']; + + if ($type == 'html') { + $htmlbody = $body; + + if ($item['title'] != "") + $htmlbody = "[b]".$item['title']."[/b]\n\n".$htmlbody; + + $htmlbody = bbcode($htmlbody, false, false, 7); + } + + $author = self::add_entry_author($doc, "author", $item["author-link"], $item); + $entry->appendChild($author); + + $dfrnowner = self::add_entry_author($doc, "dfrn:owner", $item["owner-link"], $item); + $entry->appendChild($dfrnowner); + + if(($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) { + $parent = q("SELECT `guid` FROM `item` WHERE `id` = %d", intval($item["parent"])); + $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']); + $attributes = array("ref" => $parent_item, "type" => "text/html", + "href" => app::get_baseurl().'/display/'.$parent[0]['guid'], + "dfrn:diaspora_guid" => $parent[0]['guid']); + xml_add_element($doc, $entry, "thr:in-reply-to", "", $attributes); + } + + xml_add_element($doc, $entry, "id", $item["uri"]); + xml_add_element($doc, $entry, "title", $item["title"]); + + xml_add_element($doc, $entry, "published", datetime_convert("UTC","UTC",$item["created"]."+00:00",ATOM_TIME)); + xml_add_element($doc, $entry, "updated", datetime_convert("UTC","UTC",$item["edited"]."+00:00",ATOM_TIME)); + + xml_add_element($doc, $entry, "dfrn:env", base64url_encode($body, true)); + xml_add_element($doc, $entry, "content", (($type === 'html') ? $htmlbody : $body), array("type" => $type)); + + xml_add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html", + "href" => app::get_baseurl()."/display/".$item["guid"])); + + // "comment-allow" is some old fashioned stuff for old Friendica versions. + // It is included in the rewritten code for completeness + if ($comment) + xml_add_element($doc, $entry, "dfrn:comment-allow", intval($item['last-child'])); + + if($item['location']) + xml_add_element($doc, $entry, "dfrn:location", $item['location']); + + if($item['coord']) + xml_add_element($doc, $entry, "georss:point", $item['coord']); + + if(($item['private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) + xml_add_element($doc, $entry, "dfrn:private", (($item['private']) ? $item['private'] : 1)); + + if($item['extid']) + xml_add_element($doc, $entry, "dfrn:extid", $item['extid']); + + if($item['bookmark']) + xml_add_element($doc, $entry, "dfrn:bookmark", "true"); + + if($item['app']) + xml_add_element($doc, $entry, "statusnet:notice_info", "", array("local_id" => $item['id'], "source" => $item['app'])); + + xml_add_element($doc, $entry, "dfrn:diaspora_guid", $item["guid"]); + + // The signed text contains the content in Markdown, the sender handle and the signatur for the content + // It is needed for relayed comments to Diaspora. + if($item['signed_text']) { + $sign = base64_encode(json_encode(array('signed_text' => $item['signed_text'],'signature' => $item['signature'],'signer' => $item['signer']))); + xml_add_element($doc, $entry, "dfrn:diaspora_signature", $sign); + } + + xml_add_element($doc, $entry, "activity:verb", construct_verb($item)); + + if ($item['object-type'] != "") + xml_add_element($doc, $entry, "activity:object-type", $item['object-type']); + elseif ($item['id'] == $item['parent']) + xml_add_element($doc, $entry, "activity:object-type", ACTIVITY_OBJ_NOTE); + else + xml_add_element($doc, $entry, "activity:object-type", ACTIVITY_OBJ_COMMENT); + + $actobj = self::create_activity($doc, "activity:object", $item['object']); + if ($actobj) + $entry->appendChild($actobj); + + $actarg = self::create_activity($doc, "activity:target", $item['target']); + if ($actarg) + $entry->appendChild($actarg); + + $tags = item_getfeedtags($item); + + if(count($tags)) { + foreach($tags as $t) + if (($type != 'html') OR ($t[0] != "@")) + xml_add_element($doc, $entry, "category", "", array("scheme" => "X-DFRN:".$t[0].":".$t[1], "term" => $t[2])); + } + + if(count($tags)) + foreach($tags as $t) + if ($t[0] == "@") + $mentioned[$t[1]] = $t[1]; + + foreach ($mentioned AS $mention) { + $r = q("SELECT `forum`, `prv` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s'", + intval($owner["uid"]), + dbesc(normalise_link($mention))); + if ($r[0]["forum"] OR $r[0]["prv"]) + xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned", + "ostatus:object-type" => ACTIVITY_OBJ_GROUP, + "href" => $mention)); + else + xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned", + "ostatus:object-type" => ACTIVITY_OBJ_PERSON, + "href" => $mention)); + } + + self::get_attachment($doc, $entry, $item); + + return $entry; + } + + /** + * @brief Delivers the atom content to the contacts + * + * @param array $owner Owner record + * @param array $contactr Contact record of the receiver + * @param string $atom Content that will be transmitted + * @param bool $dissolve (to be documented) + * + * @return int Deliver status. -1 means an error. + */ + function deliver($owner,$contact,$atom, $dissolve = false) { + + $a = get_app(); + + $idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']); + + if($contact['duplex'] && $contact['dfrn-id']) + $idtosend = '0:' . $orig_id; + if($contact['duplex'] && $contact['issued-id']) + $idtosend = '1:' . $orig_id; + + + $rino = get_config('system','rino_encrypt'); + $rino = intval($rino); + // use RINO1 if mcrypt isn't installed and RINO2 was selected + if ($rino==2 and !function_exists('mcrypt_create_iv')) $rino=1; + + logger("Local rino version: ". $rino, LOGGER_DEBUG); + + $ssl_val = intval(get_config('system','ssl_policy')); + $ssl_policy = ''; + + switch($ssl_val){ + case SSL_POLICY_FULL: + $ssl_policy = 'full'; + break; + case SSL_POLICY_SELFSIGN: + $ssl_policy = 'self'; + break; + case SSL_POLICY_NONE: + default: + $ssl_policy = 'none'; + break; + } + + $url = $contact['notify'] . '&dfrn_id=' . $idtosend . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . (($rino) ? '&rino='.$rino : ''); + + logger('dfrn_deliver: ' . $url); + + $xml = fetch_url($url); + + $curl_stat = $a->get_curl_code(); + if(! $curl_stat) + return(-1); // timed out + + logger('dfrn_deliver: ' . $xml, LOGGER_DATA); + + if(! $xml) + return 3; + + if(strpos($xml,'status) != 0) || (! strlen($res->challenge)) || (! strlen($res->dfrn_id))) + return (($res->status) ? $res->status : 3); + + $postvars = array(); + $sent_dfrn_id = hex2bin((string) $res->dfrn_id); + $challenge = hex2bin((string) $res->challenge); + $perm = (($res->perm) ? $res->perm : null); + $dfrn_version = (float) (($res->dfrn_version) ? $res->dfrn_version : 2.0); + $rino_remote_version = intval($res->rino); + $page = (($owner['page-flags'] == PAGE_COMMUNITY) ? 1 : 0); + + logger("Remote rino version: ".$rino_remote_version." for ".$contact["url"], LOGGER_DEBUG); + + if($owner['page-flags'] == PAGE_PRVGROUP) + $page = 2; + + $final_dfrn_id = ''; + + if($perm) { + if((($perm == 'rw') && (! intval($contact['writable']))) + || (($perm == 'r') && (intval($contact['writable'])))) { + q("update contact set writable = %d where id = %d", + intval(($perm == 'rw') ? 1 : 0), + intval($contact['id']) + ); + $contact['writable'] = (string) 1 - intval($contact['writable']); + } + } + + if(($contact['duplex'] && strlen($contact['pubkey'])) + || ($owner['page-flags'] == PAGE_COMMUNITY && strlen($contact['pubkey'])) + || ($contact['rel'] == CONTACT_IS_SHARING && strlen($contact['pubkey']))) { + openssl_public_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['pubkey']); + openssl_public_decrypt($challenge,$postvars['challenge'],$contact['pubkey']); + } else { + openssl_private_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['prvkey']); + openssl_private_decrypt($challenge,$postvars['challenge'],$contact['prvkey']); + } + + $final_dfrn_id = substr($final_dfrn_id, 0, strpos($final_dfrn_id, '.')); + + if(strpos($final_dfrn_id,':') == 1) + $final_dfrn_id = substr($final_dfrn_id,2); + + if($final_dfrn_id != $orig_id) { + logger('dfrn_deliver: wrong dfrn_id.'); + // did not decode properly - cannot trust this site + return 3; + } + + $postvars['dfrn_id'] = $idtosend; + $postvars['dfrn_version'] = DFRN_PROTOCOL_VERSION; + if($dissolve) + $postvars['dissolve'] = '1'; + + + if((($contact['rel']) && ($contact['rel'] != CONTACT_IS_SHARING) && (! $contact['blocked'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) { + $postvars['data'] = $atom; + $postvars['perm'] = 'rw'; + } else { + $postvars['data'] = str_replace('1','0',$atom); + $postvars['perm'] = 'r'; + } + + $postvars['ssl_policy'] = $ssl_policy; + + if($page) + $postvars['page'] = $page; + + + if($rino>0 && $rino_remote_version>0 && (! $dissolve)) { + logger('rino version: '. $rino_remote_version); + + switch($rino_remote_version) { + case 1: + // Deprecated rino version! + $key = substr(random_string(),0,16); + $data = aes_encrypt($postvars['data'],$key); + break; + case 2: + // RINO 2 based on php-encryption + try { + $key = Crypto::createNewRandomKey(); + } catch (CryptoTestFailed $ex) { + logger('Cannot safely create a key'); + return -1; + } catch (CannotPerformOperation $ex) { + logger('Cannot safely create a key'); + return -1; + } + try { + $data = Crypto::encrypt($postvars['data'], $key); + } catch (CryptoTestFailed $ex) { + logger('Cannot safely perform encryption'); + return -1; + } catch (CannotPerformOperation $ex) { + logger('Cannot safely perform encryption'); + return -1; + } + break; + default: + logger("rino: invalid requested verision '$rino_remote_version'"); + return -1; + } + + $postvars['rino'] = $rino_remote_version; + $postvars['data'] = bin2hex($data); + + #logger('rino: sent key = ' . $key, LOGGER_DEBUG); + + + if($dfrn_version >= 2.1) { + if(($contact['duplex'] && strlen($contact['pubkey'])) + || ($owner['page-flags'] == PAGE_COMMUNITY && strlen($contact['pubkey'])) + || ($contact['rel'] == CONTACT_IS_SHARING && strlen($contact['pubkey']))) + + openssl_public_encrypt($key,$postvars['key'],$contact['pubkey']); + else + openssl_private_encrypt($key,$postvars['key'],$contact['prvkey']); + + } else { + if(($contact['duplex'] && strlen($contact['prvkey'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) + openssl_private_encrypt($key,$postvars['key'],$contact['prvkey']); + else + openssl_public_encrypt($key,$postvars['key'],$contact['pubkey']); + + } + + logger('md5 rawkey ' . md5($postvars['key'])); + + $postvars['key'] = bin2hex($postvars['key']); + } + + + logger('dfrn_deliver: ' . "SENDING: " . print_r($postvars,true), LOGGER_DATA); + + $xml = post_url($contact['notify'],$postvars); + + logger('dfrn_deliver: ' . "RECEIVED: " . $xml, LOGGER_DATA); + + $curl_stat = $a->get_curl_code(); + if((! $curl_stat) || (! strlen($xml))) + return(-1); // timed out + + if(($curl_stat == 503) && (stristr($a->get_curl_headers(),'retry-after'))) + return(-1); + + if(strpos($xml,'status; + } +} diff --git a/include/expire.php b/include/expire.php index 308680421..873c594e8 100644 --- a/include/expire.php +++ b/include/expire.php @@ -18,7 +18,6 @@ function expire_run(&$argv, &$argc){ require_once('include/session.php'); require_once('include/datetime.php'); - require_once('library/simplepie/simplepie.inc'); require_once('include/items.php'); require_once('include/Contact.php'); diff --git a/include/items.php b/include/items.php index f17e0c05a..cf044d883 100644 --- a/include/items.php +++ b/include/items.php @@ -19,310 +19,12 @@ require_once('mod/share.php'); require_once('library/defuse/php-encryption-1.2.1/Crypto.php'); - -function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0, $forpubsub = false) { - - - $sitefeed = ((strlen($owner_nick)) ? false : true); // not yet implemented, need to rewrite huge chunks of following logic - $public_feed = (($dfrn_id) ? false : true); - $starred = false; // not yet implemented, possible security issues - $converse = false; - - if($public_feed && $a->argc > 2) { - for($x = 2; $x < $a->argc; $x++) { - if($a->argv[$x] == 'converse') - $converse = true; - if($a->argv[$x] == 'starred') - $starred = true; - if($a->argv[$x] === 'category' && $a->argc > ($x + 1) && strlen($a->argv[$x+1])) - $category = $a->argv[$x+1]; - } - } - - - - // default permissions - anonymous user - - $sql_extra = " AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' "; - - $r = q("SELECT `contact`.*, `user`.`uid` AS `user_uid`, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags` - FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` - WHERE `contact`.`self` = 1 AND `user`.`nickname` = '%s' LIMIT 1", - dbesc($owner_nick) - ); - - if(! count($r)) - killme(); - - $owner = $r[0]; - $owner_id = $owner['user_uid']; - $owner_nick = $owner['nickname']; - - $birthday = feed_birthday($owner_id,$owner['timezone']); - - $sql_post_table = ""; - $visibility = ""; - - if(! $public_feed) { - - $sql_extra = ''; - switch($direction) { - case (-1): - $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($dfrn_id)); - $my_id = $dfrn_id; - break; - case 0: - $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '1:' . $dfrn_id; - break; - case 1: - $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '0:' . $dfrn_id; - break; - default: - return false; - break; // NOTREACHED - } - - $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `contact`.`uid` = %d $sql_extra LIMIT 1", - intval($owner_id) - ); - - if(! count($r)) - killme(); - - $contact = $r[0]; - require_once('include/security.php'); - $groups = init_groups_visitor($contact['id']); - - if(count($groups)) { - for($x = 0; $x < count($groups); $x ++) - $groups[$x] = '<' . intval($groups[$x]) . '>' ; - $gs = implode('|', $groups); - } - else - $gs = '<<>>' ; // Impossible to match - - $sql_extra = sprintf(" - AND ( `allow_cid` = '' OR `allow_cid` REGEXP '<%d>' ) - AND ( `deny_cid` = '' OR NOT `deny_cid` REGEXP '<%d>' ) - AND ( `allow_gid` = '' OR `allow_gid` REGEXP '%s' ) - AND ( `deny_gid` = '' OR NOT `deny_gid` REGEXP '%s') - ", - intval($contact['id']), - intval($contact['id']), - dbesc($gs), - dbesc($gs) - ); - } - - if($public_feed) - $sort = 'DESC'; - else - $sort = 'ASC'; - - // Include answers to status.net posts in pubsub feeds - if($forpubsub) { - $sql_post_table = "INNER JOIN `thread` ON `thread`.`iid` = `item`.`parent` - LEFT JOIN `item` AS `thritem` ON `thritem`.`uri`=`item`.`thr-parent` AND `thritem`.`uid`=`item`.`uid`"; - $visibility = sprintf("AND (`item`.`parent` = `item`.`id`) OR (`item`.`network` = '%s' AND ((`thread`.`network`='%s') OR (`thritem`.`network` = '%s')))", - dbesc(NETWORK_DFRN), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_OSTATUS)); - $date_field = "`received`"; - $sql_order = "`item`.`received` DESC"; - } else { - $date_field = "`changed`"; - $sql_order = "`item`.`parent` ".$sort.", `item`.`created` ASC"; - } - - if(! strlen($last_update)) - $last_update = 'now -30 days'; - - if(isset($category)) { - $sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", - dbesc(protect_sprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($owner_id)); - //$sql_extra .= file_tag_file_query('item',$category,'category'); - } - - if($public_feed) { - if(! $converse) - $sql_extra .= " AND `contact`.`self` = 1 "; - } - - $check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s'); - - // AND ( `item`.`edited` > '%s' OR `item`.`changed` > '%s' ) - // dbesc($check_date), - - $r = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id`, - `contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`, - `contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`, - `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `contact-id`, `contact`.`uid` AS `contact-uid`, - `sign`.`signed_text`, `sign`.`signature`, `sign`.`signer` - FROM `item` $sql_post_table - INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 - LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` - WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`parent` != 0 - AND ((`item`.`wall` = 1) $visibility) AND `item`.$date_field > '%s' - $sql_extra - ORDER BY $sql_order LIMIT 0, 300", - intval($owner_id), - dbesc($check_date), - dbesc($sort) - ); - - // Will check further below if this actually returned results. - // We will provide an empty feed if that is the case. - - $items = $r; - - $feed_template = get_markup_template(($dfrn_id) ? 'atom_feed_dfrn.tpl' : 'atom_feed.tpl'); - - $atom = ''; - - $hubxml = feed_hublinks(); - - $salmon = feed_salmonlinks($owner_nick); - - $alternatelink = $owner['url']; - - if(isset($category)) - $alternatelink .= "/category/".$category; - - $atom .= replace_macros($feed_template, array( - '$version' => xmlify(FRIENDICA_VERSION), - '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner_nick), - '$feed_title' => xmlify($owner['name']), - '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now' , ATOM_TIME)) , - '$hub' => $hubxml, - '$salmon' => $salmon, - '$alternatelink' => xmlify($alternatelink), - '$name' => xmlify($owner['name']), - '$profile_page' => xmlify($owner['url']), - '$photo' => xmlify($owner['photo']), - '$thumb' => xmlify($owner['thumb']), - '$picdate' => xmlify(datetime_convert('UTC','UTC',$owner['avatar-date'] . '+00:00' , ATOM_TIME)) , - '$uridate' => xmlify(datetime_convert('UTC','UTC',$owner['uri-date'] . '+00:00' , ATOM_TIME)) , - '$namdate' => xmlify(datetime_convert('UTC','UTC',$owner['name-date'] . '+00:00' , ATOM_TIME)) , - '$birthday' => ((strlen($birthday)) ? '' . xmlify($birthday) . '' : ''), - '$community' => (($owner['page-flags'] == PAGE_COMMUNITY) ? '1' : '') - )); - - call_hooks('atom_feed', $atom); - - if(! count($items)) { - - call_hooks('atom_feed_end', $atom); - - $atom .= '' . "\r\n"; - return $atom; - } - - foreach($items as $item) { - - // prevent private email from leaking. - if($item['network'] === NETWORK_MAIL) - continue; - - // public feeds get html, our own nodes use bbcode - - if($public_feed) { - $type = 'html'; - // catch any email that's in a public conversation and make sure it doesn't leak - if($item['private']) - continue; - } - else { - $type = 'text'; - } - - $atom .= atom_entry($item,$type,null,$owner,true); - } - - call_hooks('atom_feed_end', $atom); - - $atom .= '' . "\r\n"; - - return $atom; -} - - function construct_verb($item) { if($item['verb']) return $item['verb']; return ACTIVITY_POST; } -function construct_activity_object($item) { - - if($item['object']) { - $o = '' . "\r\n"; - $r = parse_xml_string($item['object'],false); - - - if(! $r) - return ''; - if($r->type) - $o .= '' . xmlify($r->type) . '' . "\r\n"; - if($r->id) - $o .= '' . xmlify($r->id) . '' . "\r\n"; - if($r->title) - $o .= '' . xmlify($r->title) . '' . "\r\n"; - if($r->link) { - if(substr($r->link,0,1) === '<') { - // patch up some facebook "like" activity objects that got stored incorrectly - // for a couple of months prior to 9-Jun-2011 and generated bad XML. - // we can probably remove this hack here and in the following function in a few months time. - if(strstr($r->link,'&') && (! strstr($r->link,'&'))) - $r->link = str_replace('&','&', $r->link); - $r->link = preg_replace('/\/','',$r->link); - $o .= $r->link; - } - else - $o .= '' . "\r\n"; - } - if($r->content) - $o .= '' . xmlify(bbcode($r->content)) . '' . "\r\n"; - $o .= '' . "\r\n"; - return $o; - } - - return ''; -} - -function construct_activity_target($item) { - - if($item['target']) { - $o = '' . "\r\n"; - $r = parse_xml_string($item['target'],false); - if(! $r) - return ''; - if($r->type) - $o .= '' . xmlify($r->type) . '' . "\r\n"; - if($r->id) - $o .= '' . xmlify($r->id) . '' . "\r\n"; - if($r->title) - $o .= '' . xmlify($r->title) . '' . "\r\n"; - if($r->link) { - if(substr($r->link,0,1) === '<') { - if(strstr($r->link,'&') && (! strstr($r->link,'&'))) - $r->link = str_replace('&','&', $r->link); - $r->link = preg_replace('/\/','',$r->link); - $o .= $r->link; - } - else - $o .= '' . "\r\n"; - } - if($r->content) - $o .= '' . xmlify(bbcode($r->content)) . '' . "\r\n"; - $o .= '' . "\r\n"; - return $o; - } - - return ''; -} - /* limit_body_size() * * The purpose of this function is to apply system message length limits to @@ -441,8 +143,6 @@ function title_is_body($title, $body) { return($title == $body); } - - function get_atom_elements($feed, $item, $contact = array()) { require_once('library/HTMLPurifier.auto.php'); @@ -466,17 +166,6 @@ function get_atom_elements($feed, $item, $contact = array()) { $res['body'] = unxmlify($item->get_content()); $res['plink'] = unxmlify($item->get_link(0)); - if (isset($contact["network"]) AND ($contact["network"] == NETWORK_FEED) AND strstr($res['plink'], ".app.net/")) { - logger("get_atom_elements: detected app.net posting: ".print_r($res, true), LOGGER_DEBUG); - $res['title'] = ""; - $res['body'] = nl2br($res['body']); - } - - // removing the content of the title if its identically to the body - // This helps with auto generated titles e.g. from tumblr - if (title_is_body($res["title"], $res["body"])) - $res['title'] = ""; - if($res['plink']) $base_url = implode('/', array_slice(explode('/',$res['plink']),0,3)); else @@ -854,62 +543,6 @@ function get_atom_elements($feed, $item, $contact = array()) { $res['target'] .= '' . "\n"; } - // This is some experimental stuff. By now retweets are shown with "RT:" - // But: There is data so that the message could be shown similar to native retweets - // There is some better way to parse this array - but it didn't worked for me. - $child = $item->feed->data["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["feed"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["entry"][0]["child"]["http://activitystrea.ms/spec/1.0/"][object][0]["child"]; - if (is_array($child)) { - logger('get_atom_elements: Looking for status.net repeated message'); - - $message = $child["http://activitystrea.ms/spec/1.0/"]["object"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["content"][0]["data"]; - $orig_id = ostatus_convert_href($child["http://activitystrea.ms/spec/1.0/"]["object"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["id"][0]["data"]); - $author = $child[SIMPLEPIE_NAMESPACE_ATOM_10]["author"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]; - $uri = $author["uri"][0]["data"]; - $name = $author["name"][0]["data"]; - $avatar = @array_shift($author["link"][2]["attribs"]); - $avatar = $avatar["href"]; - - if (($name != "") and ($uri != "") and ($avatar != "") and ($message != "")) { - logger('get_atom_elements: fixing sender of repeated message. '.$orig_id, LOGGER_DEBUG); - - if (!intval(get_config('system','wall-to-wall_share'))) { - $prefix = share_header($name, $uri, $avatar, "", "", $orig_link); - - $res["body"] = $prefix.html2bbcode($message)."[/share]"; - } else { - $res["owner-name"] = $res["author-name"]; - $res["owner-link"] = $res["author-link"]; - $res["owner-avatar"] = $res["author-avatar"]; - - $res["author-name"] = $name; - $res["author-link"] = $uri; - $res["author-avatar"] = $avatar; - - $res["body"] = html2bbcode($message); - } - } - } - - if (isset($contact["network"]) AND ($contact["network"] == NETWORK_FEED) AND $contact['fetch_further_information']) { - $preview = ""; - - // Handle enclosures and treat them as preview picture - if (isset($attach)) - foreach ($attach AS $attachment) - if ($attachment->type == "image/jpeg") - $preview = $attachment->link; - - $res["body"] = $res["title"].add_page_info($res['plink'], false, $preview, ($contact['fetch_further_information'] == 2), $contact['ffi_keyword_blacklist']); - $res["tag"] = add_page_keywords($res['plink'], false, $preview, ($contact['fetch_further_information'] == 2), $contact['ffi_keyword_blacklist']); - $res["title"] = ""; - $res["object-type"] = ACTIVITY_OBJ_BOOKMARK; - unset($res["attach"]); - } elseif (isset($contact["network"]) AND ($contact["network"] == NETWORK_OSTATUS)) - $res["body"] = add_page_info_to_body($res["body"]); - elseif (isset($contact["network"]) AND ($contact["network"] == NETWORK_FEED) AND strstr($res['plink'], ".app.net/")) { - $res["body"] = add_page_info_to_body($res["body"]); - } - $arr = array('feed' => $feed, 'item' => $item, 'result' => $res); call_hooks('parse_atom', $arr); @@ -2063,245 +1696,9 @@ function tgroup_check($uid,$item) { if((! $community_page) && (! $prvgroup)) return false; - - return true; - } - - - - - -function dfrn_deliver($owner,$contact,$atom, $dissolve = false) { - - $a = get_app(); - - $idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']); - - if($contact['duplex'] && $contact['dfrn-id']) - $idtosend = '0:' . $orig_id; - if($contact['duplex'] && $contact['issued-id']) - $idtosend = '1:' . $orig_id; - - - $rino = get_config('system','rino_encrypt'); - $rino = intval($rino); - // use RINO1 if mcrypt isn't installed and RINO2 was selected - if ($rino==2 and !function_exists('mcrypt_create_iv')) $rino=1; - - logger("Local rino version: ". $rino, LOGGER_DEBUG); - - $ssl_val = intval(get_config('system','ssl_policy')); - $ssl_policy = ''; - - switch($ssl_val){ - case SSL_POLICY_FULL: - $ssl_policy = 'full'; - break; - case SSL_POLICY_SELFSIGN: - $ssl_policy = 'self'; - break; - case SSL_POLICY_NONE: - default: - $ssl_policy = 'none'; - break; - } - - $url = $contact['notify'] . '&dfrn_id=' . $idtosend . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . (($rino) ? '&rino='.$rino : ''); - - logger('dfrn_deliver: ' . $url); - - $xml = fetch_url($url); - - $curl_stat = $a->get_curl_code(); - if(! $curl_stat) - return(-1); // timed out - - logger('dfrn_deliver: ' . $xml, LOGGER_DATA); - - if(! $xml) - return 3; - - if(strpos($xml,'status) != 0) || (! strlen($res->challenge)) || (! strlen($res->dfrn_id))) - return (($res->status) ? $res->status : 3); - - $postvars = array(); - $sent_dfrn_id = hex2bin((string) $res->dfrn_id); - $challenge = hex2bin((string) $res->challenge); - $perm = (($res->perm) ? $res->perm : null); - $dfrn_version = (float) (($res->dfrn_version) ? $res->dfrn_version : 2.0); - $rino_remote_version = intval($res->rino); - $page = (($owner['page-flags'] == PAGE_COMMUNITY) ? 1 : 0); - - logger("Remote rino version: ".$rino_remote_version." for ".$contact["url"], LOGGER_DEBUG); - - if($owner['page-flags'] == PAGE_PRVGROUP) - $page = 2; - - $final_dfrn_id = ''; - - if($perm) { - if((($perm == 'rw') && (! intval($contact['writable']))) - || (($perm == 'r') && (intval($contact['writable'])))) { - q("update contact set writable = %d where id = %d", - intval(($perm == 'rw') ? 1 : 0), - intval($contact['id']) - ); - $contact['writable'] = (string) 1 - intval($contact['writable']); - } - } - - if(($contact['duplex'] && strlen($contact['pubkey'])) - || ($owner['page-flags'] == PAGE_COMMUNITY && strlen($contact['pubkey'])) - || ($contact['rel'] == CONTACT_IS_SHARING && strlen($contact['pubkey']))) { - openssl_public_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['pubkey']); - openssl_public_decrypt($challenge,$postvars['challenge'],$contact['pubkey']); - } - else { - openssl_private_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['prvkey']); - openssl_private_decrypt($challenge,$postvars['challenge'],$contact['prvkey']); - } - - $final_dfrn_id = substr($final_dfrn_id, 0, strpos($final_dfrn_id, '.')); - - if(strpos($final_dfrn_id,':') == 1) - $final_dfrn_id = substr($final_dfrn_id,2); - - if($final_dfrn_id != $orig_id) { - logger('dfrn_deliver: wrong dfrn_id.'); - // did not decode properly - cannot trust this site - return 3; - } - - $postvars['dfrn_id'] = $idtosend; - $postvars['dfrn_version'] = DFRN_PROTOCOL_VERSION; - if($dissolve) - $postvars['dissolve'] = '1'; - - - if((($contact['rel']) && ($contact['rel'] != CONTACT_IS_SHARING) && (! $contact['blocked'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) { - $postvars['data'] = $atom; - $postvars['perm'] = 'rw'; - } - else { - $postvars['data'] = str_replace('1','0',$atom); - $postvars['perm'] = 'r'; - } - - $postvars['ssl_policy'] = $ssl_policy; - - if($page) - $postvars['page'] = $page; - - - if($rino>0 && $rino_remote_version>0 && (! $dissolve)) { - logger('rino version: '. $rino_remote_version); - - switch($rino_remote_version) { - case 1: - // Deprecated rino version! - $key = substr(random_string(),0,16); - $data = aes_encrypt($postvars['data'],$key); - break; - case 2: - // RINO 2 based on php-encryption - try { - $key = Crypto::createNewRandomKey(); - } catch (CryptoTestFailed $ex) { - logger('Cannot safely create a key'); - return -1; - } catch (CannotPerformOperation $ex) { - logger('Cannot safely create a key'); - return -1; - } - try { - $data = Crypto::encrypt($postvars['data'], $key); - } catch (CryptoTestFailed $ex) { - logger('Cannot safely perform encryption'); - return -1; - } catch (CannotPerformOperation $ex) { - logger('Cannot safely perform encryption'); - return -1; - } - break; - default: - logger("rino: invalid requested verision '$rino_remote_version'"); - return -1; - } - - $postvars['rino'] = $rino_remote_version; - $postvars['data'] = bin2hex($data); - - #logger('rino: sent key = ' . $key, LOGGER_DEBUG); - - - if($dfrn_version >= 2.1) { - if(($contact['duplex'] && strlen($contact['pubkey'])) - || ($owner['page-flags'] == PAGE_COMMUNITY && strlen($contact['pubkey'])) - || ($contact['rel'] == CONTACT_IS_SHARING && strlen($contact['pubkey']))) { - - openssl_public_encrypt($key,$postvars['key'],$contact['pubkey']); - } - else { - openssl_private_encrypt($key,$postvars['key'],$contact['prvkey']); - } - } - else { - if(($contact['duplex'] && strlen($contact['prvkey'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) { - openssl_private_encrypt($key,$postvars['key'],$contact['prvkey']); - } - else { - openssl_public_encrypt($key,$postvars['key'],$contact['pubkey']); - } - } - - logger('md5 rawkey ' . md5($postvars['key'])); - - $postvars['key'] = bin2hex($postvars['key']); - } - - - logger('dfrn_deliver: ' . "SENDING: " . print_r($postvars,true), LOGGER_DATA); - - $xml = post_url($contact['notify'],$postvars); - - logger('dfrn_deliver: ' . "RECEIVED: " . $xml, LOGGER_DATA); - - $curl_stat = $a->get_curl_code(); - if((! $curl_stat) || (! strlen($xml))) - return(-1); // timed out - - if(($curl_stat == 503) && (stristr($a->get_curl_headers(),'retry-after'))) - return(-1); - - if(strpos($xml,'status; -} - - /* This function returns true if $update has an edited timestamp newer than $existing, i.e. $update contains new data which should override @@ -3067,6 +2464,9 @@ function item_is_remote_self($contact, &$datarray) { } function local_delivery($importer,$data) { + + require_once('library/simplepie/simplepie.inc'); + $a = get_app(); logger(__function__, LOGGER_TRACE); @@ -4340,7 +3740,6 @@ function lose_sharer($importer,$contact,$datarray,$item) { } } - function subscribe_to_hub($url,$importer,$contact,$hubmode = 'subscribe') { $a = get_app(); @@ -4383,189 +3782,6 @@ function subscribe_to_hub($url,$importer,$contact,$hubmode = 'subscribe') { } - -function atom_author($tag,$name,$uri,$h,$w,$photo,$geo) { - $o = ''; - if(! $tag) - return $o; - $name = xmlify($name); - $uri = xmlify($uri); - $h = intval($h); - $w = intval($w); - $photo = xmlify($photo); - - - $o .= "<$tag>\r\n"; - $o .= "\t$name\r\n"; - $o .= "\t$uri\r\n"; - $o .= "\t".'' . "\r\n"; - $o .= "\t".'' . "\r\n"; - - if ($tag == "author") { - - if($geo) - $o .= ''.xmlify($geo).''."\r\n"; - - $r = q("SELECT `profile`.`locality`, `profile`.`region`, `profile`.`country-name`, - `profile`.`name`, `profile`.`pub_keywords`, `profile`.`about`, - `profile`.`homepage`,`contact`.`nick` FROM `profile` - INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` - INNER JOIN `user` ON `user`.`uid` = `profile`.`uid` - WHERE `profile`.`is-default` AND `contact`.`self` AND - NOT `user`.`hidewall` AND `contact`.`nurl`='%s'", - dbesc(normalise_link($uri))); - if ($r) { - $location = ''; - if($r[0]['locality']) - $location .= $r[0]['locality']; - if($r[0]['region']) { - if($location) - $location .= ', '; - $location .= $r[0]['region']; - } - if($r[0]['country-name']) { - if($location) - $location .= ', '; - $location .= $r[0]['country-name']; - } - - $o .= "\t".xmlify($r[0]["nick"])."\r\n"; - $o .= "\t".xmlify($r[0]["name"])."\r\n"; - $o .= "\t".xmlify(bbcode($r[0]["about"]))."\r\n"; - $o .= "\t\r\n"; - $o .= "\t\t".xmlify($location)."\r\n"; - $o .= "\t\r\n"; - $o .= "\t\r\n"; - $o .= "\thomepage\r\n"; - $o .= "\t\t".xmlify($r[0]["homepage"])."\r\n"; - $o .= "\t\ttrue\r\n"; - $o .= "\t\r\n"; - } - } - - call_hooks('atom_author', $o); - - $o .= "\r\n"; - return $o; -} - -function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { - - $a = get_app(); - - if(! $item['parent']) - return; - - if($item['deleted']) - return '' . "\r\n"; - - - 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']; - - - $o = "\r\n\r\n\r\n"; - - if(is_array($author)) - $o .= atom_author('author',$author['name'],$author['url'],80,80,$author['thumb'], $item['coord']); - else - $o .= atom_author('author',(($item['author-name']) ? $item['author-name'] : $item['name']),(($item['author-link']) ? $item['author-link'] : $item['url']),80,80,(($item['author-avatar']) ? $item['author-avatar'] : $item['thumb']), $item['coord']); - if(strlen($item['owner-name'])) - $o .= atom_author('dfrn:owner',$item['owner-name'],$item['owner-link'],80,80,$item['owner-avatar'], $item['coord']); - - if(($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) { - $parent = q("SELECT `guid` FROM `item` WHERE `id` = %d", intval($item["parent"])); - $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']); - $o .= ''."\r\n"; - } - - $htmlbody = $body; - - if ($item['title'] != "") - $htmlbody = "[b]".$item['title']."[/b]\n\n".$htmlbody; - - $htmlbody = bbcode($htmlbody, false, false, 7); - - $o .= '' . xmlify($item['uri']) . '' . "\r\n"; - $o .= '' . xmlify($item['title']) . '' . "\r\n"; - $o .= '' . xmlify(datetime_convert('UTC','UTC',$item['created'] . '+00:00',ATOM_TIME)) . '' . "\r\n"; - $o .= '' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '' . "\r\n"; - $o .= '' . base64url_encode($body, true) . '' . "\r\n"; - $o .= '' . xmlify((($type === 'html') ? $htmlbody : $body)) . '' . "\r\n"; - $o .= ''."\r\n"; - - $o .= ''."\r\n"; - - if($comment) - $o .= '' . intval($item['last-child']) . '' . "\r\n"; - - if($item['location']) { - $o .= '' . xmlify($item['location']) . '' . "\r\n"; - $o .= '' . xmlify($item['location']) . '' . "\r\n"; - } - - if($item['coord']) - $o .= '' . xmlify($item['coord']) . '' . "\r\n"; - - if(($item['private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) - $o .= '' . (($item['private']) ? $item['private'] : 1) . '' . "\r\n"; - - if($item['extid']) - $o .= '' . xmlify($item['extid']) . '' . "\r\n"; - if($item['bookmark']) - $o .= 'true' . "\r\n"; - - if($item['app']) - $o .= '' . "\r\n"; - - if($item['guid']) - $o .= '' . $item['guid'] . '' . "\r\n"; - - if($item['signed_text']) { - $sign = base64_encode(json_encode(array('signed_text' => $item['signed_text'],'signature' => $item['signature'],'signer' => $item['signer']))); - $o .= '' . xmlify($sign) . '' . "\r\n"; - } - - $verb = construct_verb($item); - $o .= '' . xmlify($verb) . '' . "\r\n"; - $actobj = construct_activity_object($item); - if(strlen($actobj)) - $o .= $actobj; - $actarg = construct_activity_target($item); - if(strlen($actarg)) - $o .= $actarg; - - $tags = item_getfeedtags($item); - if(count($tags)) { - foreach($tags as $t) - if (($type != 'html') OR ($t[0] != "@")) - $o .= '' . "\r\n"; - } - - /// @TODO - /// To support these elements, the API needs to be enhanced - /// $o .= ''."\r\n"; - /// $o .= "\t".''."\r\n"; - /// $o .= "\t".''."\r\n"; - - // Deactivated since it was meant only for OStatus - //$o .= item_get_attachment($item); - - $o .= item_getfeedattach($item); - - $mentioned = get_mentions($item); - if($mentioned) - $o .= $mentioned; - - call_hooks('atom_entry', $o); - - $o .= '' . "\r\n"; - - return $o; -} - function fix_private_photos($s, $uid, $item = null, $cid = 0) { if(get_config('system','disable_embedded')) @@ -4669,7 +3885,6 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) { return($new_body); } - function has_permissions($obj) { if(($obj['allow_cid'] != '') || ($obj['allow_gid'] != '') || ($obj['deny_cid'] != '') || ($obj['deny_gid'] != '')) return true; @@ -4730,50 +3945,6 @@ function item_getfeedtags($item) { return $ret; } -function item_get_attachment($item) { - $o = ""; - $siteinfo = get_attached_data($item["body"]); - - switch($siteinfo["type"]) { - case 'link': - $o = ''."\r\n"; - break; - case 'photo': - $imgdata = get_photo_info($siteinfo["image"]); - $o = ''."\r\n"; - break; - case 'video': - $o = ''."\r\n"; - break; - default: - break; - } - - return $o; -} - -function item_getfeedattach($item) { - $ret = ''; - $arr = explode('[/attach],',$item['attach']); - if(count($arr)) { - foreach($arr as $r) { - $matches = false; - $cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|',$r,$matches); - if($cnt) { - $ret .= 'createElement($element, xmlify($value)); foreach ($attributes AS $key => $value) { @@ -1129,7 +1129,11 @@ function xml_add_element($doc, $parent, $element, $value = "", $attributes = arr $attribute->value = xmlify($value); $element->appendChild($attribute); } + return $element; +} +function xml_add_element($doc, $parent, $element, $value = "", $attributes = array()) { + $element = xml_create_element($doc, $element, $value, $attributes); $parent->appendChild($element); } diff --git a/include/profile_update.php b/include/profile_update.php index 0fcf3617f..7cc72cc86 100644 --- a/include/profile_update.php +++ b/include/profile_update.php @@ -3,6 +3,7 @@ require_once('include/datetime.php'); require_once('include/diaspora.php'); require_once('include/queue_fn.php'); +require_once('include/Contact.php'); function profile_change() { @@ -53,19 +54,7 @@ function profile_change() { $about = xmlify($profile['about']); require_once('include/bbcode.php'); $about = xmlify(strip_tags(bbcode($about))); - $location = ''; - if($profile['locality']) - $location .= $profile['locality']; - if($profile['region']) { - if($location) - $location .= ', '; - $location .= $profile['region']; - } - if($profile['country-name']) { - if($location) - $location .= ', '; - $location .= $profile['country-name']; - } + $location = formatted_location($profile); $location = xmlify($location); $tags = ''; if($profile['pub_keywords']) { diff --git a/include/queue.php b/include/queue.php index f40768f0d..1525ca3ab 100644 --- a/include/queue.php +++ b/include/queue.php @@ -1,6 +1,7 @@ '); - $deliver_status = dfrn_deliver($owner,$contact,$data); + $deliver_status = dfrn::deliver($owner,$contact,$data); if($deliver_status == (-1)) { update_queue_time($q_item['id']); diff --git a/include/text.php b/include/text.php index fc5e79294..62d4bf151 100644 --- a/include/text.php +++ b/include/text.php @@ -829,35 +829,6 @@ function qp($s) { return str_replace ("%","=",rawurlencode($s)); }} - - -if(! function_exists('get_mentions')) { -/** - * @param array $item - * @return string html for mentions #FIXME: remove html - */ -function get_mentions($item) { - $o = ''; - if(! strlen($item['tag'])) - return $o; - - $arr = explode(',',$item['tag']); - foreach($arr as $x) { - $matches = null; - if(preg_match('/@\[url=([^\]]*)\]/',$x,$matches)) { - $o .= "\t\t" . '' . "\r\n"; - $o .= "\t\t" . '' . "\r\n"; - } - } - - if (!$item['private']) { - $o .= "\t\t".''."\r\n"; - $o .= "\t\t".''."\r\n"; - } - - return $o; -}} - if(! function_exists('contact_block')) { /** * Get html for contact block. @@ -1657,54 +1628,6 @@ function get_cats_and_terms($item) { return array($categories, $folders); } - - -if(! function_exists('feed_hublinks')) { -/** - * return atom link elements for all of our hubs - * @return string hub link xml elements - */ -function feed_hublinks() { - $a = get_app(); - $hub = get_config('system','huburl'); - - $hubxml = ''; - if(strlen($hub)) { - $hubs = explode(',', $hub); - if(count($hubs)) { - foreach($hubs as $h) { - $h = trim($h); - if(! strlen($h)) - continue; - if ($h === '[internal]') - $h = z_root() . '/pubsubhubbub'; - $hubxml .= '' . "\n" ; - } - } - } - return $hubxml; -}} - - -if(! function_exists('feed_salmonlinks')) { -/** - * return atom link elements for salmon endpoints - * @param string $nick user nickname - * @return string salmon link xml elements - */ -function feed_salmonlinks($nick) { - - $a = get_app(); - - $salmon = '' . "\n" ; - - // old style links that status.net still needed as of 12/2010 - - $salmon .= ' ' . "\n" ; - $salmon .= ' ' . "\n" ; - return $salmon; -}} - if(! function_exists('get_plink')) { /** * get private link for item diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index fcc572654..4aa777b55 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -1,6 +1,5 @@ argv[1], $last_update, $direction); + $o = dfrn::feed($dfrn_id, $a->argv[1], $last_update, $direction); echo $o; killme(); diff --git a/mod/profiles.php b/mod/profiles.php index 3ba57c883..5c372de8e 100644 --- a/mod/profiles.php +++ b/mod/profiles.php @@ -1,5 +1,5 @@ $locality, "region" => $region, "country-name" => $country_name)); $r = q("UPDATE `contact` SET `about` = '%s', `location` = '%s', `keywords` = '%s', `gender` = '%s' WHERE `self` = 1 AND `uid` = %d", dbesc($about), diff --git a/view/templates/atom_feed.tpl b/view/templates/atom_feed.tpl deleted file mode 100644 index 7070f4c5e..000000000 --- a/view/templates/atom_feed.tpl +++ /dev/null @@ -1,31 +0,0 @@ - - - - - {{$feed_id}} - {{$feed_title}} - Friendica - - - {{$hub}} - {{$salmon}} - {{$community}} - - {{$feed_updated}} - - - {{$name}} - {{$profile_page}} - - - {{$birthday}} - diff --git a/view/templates/atom_feed_dfrn.tpl b/view/templates/atom_feed_dfrn.tpl deleted file mode 100644 index 2b1c16fb3..000000000 --- a/view/templates/atom_feed_dfrn.tpl +++ /dev/null @@ -1,31 +0,0 @@ - - - - - {{$feed_id}} - {{$feed_title}} - Friendica - - - {{$hub}} - {{$salmon}} - {{$community}} - - {{$feed_updated}} - - - {{$name}} - {{$profile_page}} - - - {{$birthday}} - diff --git a/view/templates/atom_mail.tpl b/view/templates/atom_mail.tpl deleted file mode 100644 index e18e47655..000000000 --- a/view/templates/atom_mail.tpl +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - {{$name}} - {{$profile_page}} - {{$thumb}} - - - {{$item_id}} - {{$parent_id}} - {{$created}} - {{$subject}} - {{$content}} - - - diff --git a/view/templates/atom_relocate.tpl b/view/templates/atom_relocate.tpl deleted file mode 100644 index e6418fcb2..000000000 --- a/view/templates/atom_relocate.tpl +++ /dev/null @@ -1,18 +0,0 @@ - - - - - {{$url}} - {{$name}} - {{$photo}} - {{$thumb}} - {{$micro}} - {{$request}} - {{$confirm}} - {{$notify}} - {{$poll}} - {{$sitepubkey}} - - - - diff --git a/view/templates/atom_suggest.tpl b/view/templates/atom_suggest.tpl deleted file mode 100644 index afc1d6629..000000000 --- a/view/templates/atom_suggest.tpl +++ /dev/null @@ -1,12 +0,0 @@ - - - - - {{$url}} - {{$name}} - {{$photo}} - {{$request}} - {{$note}} - - -